home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung 2 / Power-Programmierung CD 2 (Tewi)(1994).iso / gnu / djgpp / src / gas-211 / gas / config / tc-mips.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-30  |  81.5 KB  |  3,421 lines

  1. /* tc-mips.c -- assemble code for a MIPS chip.
  2.    Copyright (C) 1993 Free Software Foundation, Inc.
  3.    Contributed by the OSF and Ralph Campbell.
  4.    Written by Keith Knowles and Ralph Campbell, working independently.
  5.    Modified for ECOFF support by Ian Lance Taylor of Cygnus Support.
  6.  
  7.    This file is part of GAS.
  8.  
  9.    GAS is free software; you can redistribute it and/or modify
  10.    it under the terms of the GNU General Public License as published by
  11.    the Free Software Foundation; either version 2, or (at your option)
  12.    any later version.
  13.  
  14.    GAS is distributed in the hope that it will be useful,
  15.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.    GNU General Public License for more details.
  18.  
  19.    You should have received a copy of the GNU General Public License
  20.    along with GAS; see the file COPYING.  If not, write to
  21.    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  22.  
  23. #include "as.h"
  24.  
  25. #include <ctype.h>
  26.  
  27. #ifndef __STDC__
  28. #ifndef NO_STDARG
  29. #define NO_STDARG
  30. #endif
  31. #endif
  32.  
  33. #ifndef NO_STDARG
  34. #include <stdarg.h>
  35. #else
  36. #ifndef NO_VARARGS
  37. #include <varargs.h>
  38. #endif /* NO_VARARGS */
  39. #endif /* NO_STDARG */
  40.  
  41. #include "mips-opcode.h"
  42.  
  43. #define AT  1
  44. #define GP  28
  45. #define RA  31
  46.  
  47. static int mips_warn_about_macros;
  48. static int mips_noreorder;
  49. static int mips_nomove;
  50. static int mips_noat;
  51. static int mips_nobopt;
  52.  
  53. #ifdef OBJ_ECOFF
  54. /* The size of the small data section.  */
  55. static int g_switch_value = 8;
  56. #endif
  57.  
  58. #define N_RMASK 0xc4
  59. #define N_VFP   0xd4
  60.  
  61. /* handle of the OPCODE hash table */
  62. static struct hash_control *op_hash = NULL;
  63.  
  64. /* This array holds the chars that always start a comment.  If the
  65.     pre-processor is disabled, these aren't very useful */
  66. const char comment_chars[] = "#";
  67.  
  68. /* This array holds the chars that only start a comment at the beginning of
  69.    a line.  If the line seems to have the form '# 123 filename'
  70.    .line and .file directives will appear in the pre-processed output */
  71. /* Note that input_file.c hand checks for '#' at the beginning of the
  72.    first line of the input file.  This is because the compiler outputs
  73.    #NO_APP at the beginning of its output. */
  74. /* Also note that C style comments are always supported.  */
  75. const char line_comment_chars[] = "#";
  76.  
  77. /* This array holds machine specific line separator characters. */
  78. const char line_separator_chars[] = "";
  79.  
  80. /* Chars that can be used to separate mant from exp in floating point nums */
  81. const char EXP_CHARS[] = "eE";
  82.  
  83. /* Chars that mean this number is a floating point constant */
  84. /* As in 0f12.456 */
  85. /* or    0d1.2345e12 */
  86. const char FLT_CHARS[] = "rRsSfFdDxXpP";
  87.  
  88. /* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
  89.    changed in read.c .  Ideally it shouldn't have to know about it at all,
  90.    but nothing is ideal around here.
  91.  */
  92.  
  93. static char *insn_error;
  94.  
  95. static int byte_order = BYTE_ORDER;
  96.  
  97. static int auto_align = 1;
  98.  
  99. /* Prototypes for static functions.  */
  100.  
  101. #ifdef __STDC__
  102. #define internalError() \
  103.     as_fatal ("internal Error, line %d, %s", __LINE__, __FILE__)
  104. #else
  105. #define internalError() as_fatal ("MIPS internal Error");
  106. #endif
  107.  
  108. static void append_insn PARAMS ((struct mips_cl_insn * ip,
  109.                  expressionS * p,
  110.                  bfd_reloc_code_real_type r));
  111. static int gp_reference PARAMS ((expressionS * ep));
  112. static void macro_build PARAMS ((int *counter, expressionS * ep,
  113.                  const char *name, const char *fmt,
  114.                  ...));
  115. static void macro_build_lui PARAMS ((int *counter, expressionS * ep,
  116.                      int regnum));
  117. static void set_at PARAMS ((int *counter, int reg));
  118. static void set_at_unsigned PARAMS ((int *counter, int reg));
  119. static void check_absolute_expr PARAMS ((struct mips_cl_insn * ip,
  120.                      expressionS * expr));
  121. static void load_register PARAMS ((int *counter,
  122.                    struct mips_cl_insn * ip,
  123.                    int reg, expressionS * ep));
  124. static void macro PARAMS ((struct mips_cl_insn * ip));
  125. static void mips_ip PARAMS ((char *str, struct mips_cl_insn * ip));
  126. static int my_getSmallExpression PARAMS ((expressionS * ep, char *str));
  127. static void my_getExpression PARAMS ((expressionS * ep, char *str));
  128. static symbolS *get_symbol PARAMS ((void));
  129. static long get_optional_absolute_expression PARAMS ((void));
  130. static void s_align PARAMS ((int));
  131. static void s_change_sec PARAMS ((int));
  132. static void s_cons PARAMS ((int));
  133. static void s_err PARAMS ((int));
  134. static void s_extern PARAMS ((int));
  135. static void s_float_cons PARAMS ((int));
  136. static void s_option PARAMS ((int));
  137. static void s_mipsset PARAMS ((int));
  138. #ifndef OBJ_ECOFF
  139. static void md_obj_begin PARAMS ((void));
  140. static void md_obj_end PARAMS ((void));
  141. static long get_number PARAMS ((void));
  142. static void s_ent PARAMS ((int));
  143. static void s_mipsend PARAMS ((int));
  144. static void s_file PARAMS ((int));
  145. static void s_frame PARAMS ((int));
  146. static void s_loc PARAMS ((int));
  147. static void s_mask PARAMS ((char));
  148. #endif
  149.  
  150. /* Pseudo-op table.
  151.  
  152.    The following pseudo-ops from the Kane and Heinrich MIPS book
  153.    should be defined here, but are currently unsupported: .alias,
  154.    .galive, .gjaldef, .gjrlive, .livereg, .noalias.
  155.  
  156.    The following pseudo-ops from the Kane and Heinrich MIPS book are
  157.    specific to the type of debugging information being generated, and
  158.    should be defined by the object format: .aent, .begin, .bend,
  159.    .bgnb, .end, .endb, .ent, .fmask, .frame, .loc, .mask, .verstamp,
  160.    .vreg.
  161.  
  162.    The following pseudo-ops from the Kane and Heinrich MIPS book are
  163.    not MIPS CPU specific, but are also not specific to the object file
  164.    format.  This file is probably the best place to define them, but
  165.    they are not currently supported: .asm0, .endr, .lab, .repeat,
  166.    .struct, .weakext.  */
  167.  
  168. const pseudo_typeS md_pseudo_table[] =
  169. {
  170.  /* MIPS specific pseudo-ops.  */
  171.   {"option", s_option, 0},
  172.   {"set", s_mipsset, 0},
  173.   {"rdata", s_change_sec, 'r',},
  174.   {"sdata", s_change_sec, 's',},
  175.  
  176.  /* Relatively generic pseudo-ops that happen to be used on MIPS
  177.      chips.  */
  178.   {"asciiz", stringer, 1},
  179.   {"bss", s_change_sec, 'b'},
  180.   {"err", s_err, 0},
  181.   {"half", s_cons, 1},
  182.  
  183.  /* These pseudo-ops are defined in read.c, but must be overridden
  184.      here for one reason or another.  */
  185.   {"align", s_align, 0},
  186.   {"byte", s_cons, 0},
  187.   {"data", s_change_sec, 'd'},
  188.   {"double", s_float_cons, 1},
  189.   {"extern", s_extern, 0},
  190.   {"float", s_float_cons, 0},
  191.   {"text", s_change_sec, 't'},
  192.   {"word", s_cons, 2},
  193.  
  194. #ifndef OBJ_ECOFF
  195.  /* These pseudo-ops should be defined by the object file format.
  196.      However, ECOFF is the only format which currently defines them,
  197.      so we have versions here for a.out.  */
  198.   {"aent", s_ent, 1},
  199.   {"end", s_mipsend, 0},
  200.   {"ent", s_ent, 0},
  201.   {"file", s_file, 0},
  202.   {"fmask", s_ignore, 'F'},
  203.   {"frame", s_ignore, 0},
  204.   {"loc", s_ignore, 0},
  205.   {"mask", s_ignore, 'R'},
  206.   {"verstamp", s_ignore, 0},
  207. #endif
  208.  
  209.  /* Sentinel.  */
  210.   {NULL}
  211. };
  212.  
  213. const relax_typeS md_relax_table[] =
  214. {
  215.   0
  216. };
  217.  
  218.  
  219. static char *expr_end;
  220.  
  221. static expressionS imm_expr;
  222. static expressionS offset_expr;
  223. static bfd_reloc_code_real_type imm_reloc;
  224. static bfd_reloc_code_real_type offset_reloc;
  225.  
  226. /*
  227.  * This function is called once, at assembler startup time.  It should
  228.  * set up all the tables, etc. that the MD part of the assembler will need.
  229.  */
  230. void
  231. md_begin ()
  232. {
  233.   register char *retval = NULL;
  234.   register unsigned int i = 0;
  235.  
  236.   if ((op_hash = hash_new ()) == NULL)
  237.     {
  238.       as_fatal ("Virtual memory exhausted");
  239.     }
  240.   for (i = 0; i < NUMOPCODES;)
  241.     {
  242.       const char *name = mips_opcodes[i].name;
  243.  
  244.       retval = hash_insert (op_hash, name, &mips_opcodes[i]);
  245.       if (retval != NULL && *retval != '\0')
  246.     {
  247.       fprintf (stderr, "internal error: can't hash `%s': %s\n",
  248.            mips_opcodes[i].name, retval);
  249.       as_fatal ("Broken assembler.  No assembly attempted.");
  250.     }
  251.       do
  252.     {
  253.       if ((mips_opcodes[i].match & mips_opcodes[i].mask) !=
  254.           mips_opcodes[i].match)
  255.         {
  256.           fprintf (stderr, "internal error: bad opcode: `%s' \"%s\"\n",
  257.                mips_opcodes[i].name, mips_opcodes[i].args);
  258.           as_fatal ("Broken assembler.  No assembly attempted.");
  259.         }
  260.       ++i;
  261.     }
  262.       while ((i < NUMOPCODES) && !strcmp (mips_opcodes[i].name, name));
  263.     }
  264.  
  265. #ifndef OBJ_ECOFF
  266.   md_obj_begin ();
  267. #endif
  268. }
  269.  
  270. void
  271. md_end ()
  272. {
  273. #ifndef OBJ_ECOFF
  274.   md_obj_end ();
  275. #endif
  276. }
  277.  
  278. void
  279. md_assemble (str)
  280.      char *str;
  281. {
  282.   struct mips_cl_insn insn;
  283.   static int init;
  284.  
  285.   if (!init)
  286.     {
  287.       /* set the default alignment for the text section (2**2) */
  288.       /* This should go in md_begin but text_section isn't initialized then */
  289.       record_alignment (text_section, 2);
  290.       bfd_set_gp_size (stdoutput, g_switch_value);
  291.       init = 1;
  292.     }
  293.  
  294.   imm_expr.X_seg = absent_section;
  295.   offset_expr.X_seg = absent_section;
  296.  
  297.   mips_ip (str, &insn);
  298.   if (insn_error)
  299.     {
  300.       as_bad ("%s `%s'", insn_error, str);
  301.       return;
  302.     }
  303.   if (insn.insn_mo->pinfo == INSN_MACRO)
  304.     {
  305.       macro (&insn);
  306.     }
  307.   else
  308.     {
  309.       if (imm_expr.X_seg != absent_section)
  310.     append_insn (&insn, &imm_expr, imm_reloc);
  311.       else if (offset_expr.X_seg != absent_section)
  312.     append_insn (&insn, &offset_expr, offset_reloc);
  313.       else
  314.     append_insn (&insn, NULL, BFD_RELOC_UNUSED);
  315.     }
  316. }
  317.  
  318. #define ALIGN_ERR "Attempt to assemble instruction onto non word boundary."
  319. #define ALIGN_ERR2 "GAS doesn't do implicit alignment; use .align directive."
  320.  
  321. /*
  322.  *                                append insn
  323.  * Output an instruction.
  324.  */
  325. static void
  326. append_insn (ip, address_expr, reloc_type)
  327.      struct mips_cl_insn *ip;
  328.      expressionS *address_expr;
  329.      bfd_reloc_code_real_type reloc_type;
  330. {
  331.   char *f;
  332.  
  333.   f = frag_more (4);
  334. #if 0                /* This is testing the address of the frag, not the alignment of
  335.      the instruction in the current section.  */
  336.   if ((int) f & 3)
  337.     {
  338.       as_bad (ALIGN_ERR);
  339.       as_bad (ALIGN_ERR2);
  340.     }
  341. #endif
  342.   if (address_expr != NULL)
  343.     {
  344.       fixS *fixP;
  345.  
  346.       if (address_expr->X_seg == &bfd_abs_section)
  347.     {
  348.       switch (reloc_type)
  349.         {
  350.         case BFD_RELOC_32:
  351.           ip->insn_opcode |= address_expr->X_add_number;
  352.           break;
  353.  
  354.         case BFD_RELOC_LO16:
  355.           ip->insn_opcode |= address_expr->X_add_number & 0xffff;
  356.           break;
  357.  
  358.         case BFD_RELOC_MIPS_JMP:
  359.         case BFD_RELOC_16_PCREL_S2:
  360.           goto need_reloc;
  361.  
  362.         default:
  363.           internalError ();
  364.         }
  365.     }
  366.       else
  367.     {
  368.       assert (reloc_type != BFD_RELOC_UNUSED);
  369.     need_reloc:
  370.       fixP = fix_new (frag_now, f - frag_now->fr_literal, 4,
  371.               address_expr->X_add_symbol,
  372.               address_expr->X_subtract_symbol,
  373.               address_expr->X_add_number,
  374.               reloc_type == BFD_RELOC_16_PCREL_S2,
  375.               reloc_type);
  376.     }
  377.     }
  378.   md_number_to_chars (f, ip->insn_opcode, 4);
  379.  
  380.   /*
  381.    * Fill all delay slots with nops.
  382.    */
  383.   if (!mips_noreorder)
  384.     {
  385.       if (ip->insn_mo->pinfo & ANY_DELAY)
  386.     {
  387.       f = frag_more (4);
  388.       md_number_to_chars (f, 0, 4);
  389.     };
  390.  
  391.       /* One extra nop */
  392.       if (ip->insn_mo->pinfo & INSN_EXTRA_DELAY)
  393.     {
  394.       f = frag_more (4);
  395.       md_number_to_chars (f, 0, 4);
  396.     }
  397.     }
  398. }
  399.  
  400. /* Return 1 if an expression can be accessed via the GP register.  */
  401.  
  402. static int
  403. gp_reference (ep)
  404.      expressionS *ep;
  405. {
  406. #ifdef OBJ_ECOFF
  407.   symbolS *sym;
  408.   const char *symname;
  409.   const char *segname;
  410.  
  411.   sym = ep->X_add_symbol;
  412.   if (sym == (symbolS *) NULL
  413.       || ep->X_subtract_symbol != (symbolS *) NULL)
  414.     return 0;
  415.  
  416.   /* Certain symbols can not be referenced off the GP, although it
  417.      appears as though they can.  */
  418.   symname = S_GET_NAME (sym);
  419.   if (symname != (const char *) NULL
  420.       && (strcmp (symname, "eprol") == 0
  421.       || strcmp (symname, "etext") == 0
  422.       || strcmp (symname, "_gp") == 0
  423.       || strcmp (symname, "edata") == 0
  424.       || strcmp (symname, "_fbss") == 0
  425.       || strcmp (symname, "_fdata") == 0
  426.       || strcmp (symname, "_ftext") == 0
  427.       || strcmp (symname, "end") == 0))
  428.     return 0;
  429.   if (! S_IS_DEFINED (sym)
  430.       && S_GET_VALUE (sym) != 0
  431.       && S_GET_VALUE (sym) <= g_switch_value)
  432.     return 1;
  433.   segname = segment_name (S_GET_SEGMENT (ep->X_add_symbol));
  434.   return (strcmp (segname, ".sdata") == 0
  435.       || strcmp (segname, ".sbss") == 0);
  436. #else /* ! defined (OBJ_ECOFF) */
  437.   /* The GP register is only used for ECOFF.  */
  438.   return 0;
  439. #endif /* ! defined (OBJ_ECOFF) */  
  440. }
  441.  
  442. /* Build an instruction created by a macro expansion.  This is passed
  443.    a pointer to the count of instructions created so far, an
  444.    expression, the name of the instruction to build, an operand format
  445.    string, and corresponding arguments.  */
  446.  
  447. #ifndef NO_STDARG
  448. static void
  449. macro_build (int *counter,
  450.          expressionS * ep,
  451.          const char *name,
  452.          const char *fmt,
  453.          ...)
  454. #else /* ! defined (NO_STDARG) */
  455. static void
  456. macro_build (counter, ep, name, fmt, va_alist)
  457.      int *counter;
  458.      expressionS *ep;
  459.      const char *name;
  460.      const char *fmt;
  461.      va_dcl
  462. #endif /* ! defined (NO_STDARG) */
  463. {
  464.   struct mips_cl_insn insn;
  465.   bfd_reloc_code_real_type r;
  466.   va_list args;
  467.  
  468. #ifndef NO_STDARG
  469.   va_start (args, fmt);
  470. #else
  471.   va_start (args);
  472. #endif
  473.  
  474.   /*
  475.    * If the macro is about to expand into a second instruction,
  476.    * print a warning if needed. We need to pass ip as a parameter
  477.    * to generate a better warning message here...
  478.    */
  479.   if (mips_warn_about_macros && *counter == 1)
  480.     as_warn ("Macro instruction expanded into multiple instructions");
  481.  
  482.   *counter += 1;        /* bump instruction counter */
  483.  
  484.   r = BFD_RELOC_UNUSED;
  485.   insn.insn_mo = (struct mips_opcode *) hash_find (op_hash, name);
  486.   assert (insn.insn_mo);
  487.   assert (strcmp (name, insn.insn_mo->name) == 0);
  488.  
  489.   while (strcmp (fmt, insn.insn_mo->args) != 0)
  490.     {
  491.       ++insn.insn_mo;
  492.       assert (insn.insn_mo->name);
  493.       assert (strcmp (name, insn.insn_mo->name) == 0);
  494.     }
  495.   assert (insn.insn_mo->pinfo != INSN_MACRO);
  496.   insn.insn_opcode = insn.insn_mo->match;
  497.   for (;;)
  498.     {
  499.       switch (*fmt++)
  500.     {
  501.     case '\0':
  502.       break;
  503.  
  504.     case ',':
  505.     case '(':
  506.     case ')':
  507.       continue;
  508.  
  509.     case 't':
  510.     case 'w':
  511.       insn.insn_opcode |= va_arg (args, int) << 16;
  512.       continue;
  513.  
  514.     case 'c':
  515.     case 'T':
  516.     case 'W':
  517.       insn.insn_opcode |= va_arg (args, int) << 16;
  518.       continue;
  519.  
  520.     case 'd':
  521.       insn.insn_opcode |= va_arg (args, int) << 11;
  522.       continue;
  523.  
  524.     case 'V':
  525.     case 'S':
  526.       insn.insn_opcode |= va_arg (args, int) << 11;
  527.       continue;
  528.  
  529.     case '<':
  530.       insn.insn_opcode |= va_arg (args, int) << 6;
  531.       continue;
  532.  
  533.     case 'D':
  534.       insn.insn_opcode |= va_arg (args, int) << 6;
  535.       continue;
  536.  
  537.     case 'b':
  538.     case 's':
  539.     case 'r':
  540.     case 'v':
  541.       insn.insn_opcode |= va_arg (args, int) << 21;
  542.       continue;
  543.  
  544.     case 'i':
  545.     case 'j':
  546.     case 'o':
  547.       r = BFD_RELOC_LO16;
  548.       continue;
  549.  
  550.     case 'p':
  551.       assert (ep != NULL);
  552.       /*
  553.        * This allows macro() to pass an immediate expression for
  554.        * creating short branches without creating a symbol.
  555.        * Note that the expression still might come from the assembly
  556.        * input, in which case the value is not checked for range nor
  557.        * is a relocation entry generated (yuck).
  558.        */
  559.       if (ep->X_add_symbol == NULL && ep->X_seg == &bfd_abs_section)
  560.         {
  561.           insn.insn_opcode |= (ep->X_add_number >> 2) & 0xffff;
  562.           ep = NULL;
  563.         }
  564.       else
  565.         r = BFD_RELOC_16_PCREL_S2;
  566.       continue;
  567.  
  568.     default:
  569.       internalError ();
  570.     }
  571.       break;
  572.     }
  573.   va_end (args);
  574.   assert (r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
  575.  
  576.   /* Use GP relative addressing if possible.  */
  577.   if (r == BFD_RELOC_LO16
  578.       && gp_reference (ep))
  579.     r = BFD_RELOC_MIPS_GPREL;
  580.  
  581.   append_insn (&insn, ep, r);
  582. }
  583.  
  584. /*
  585.  * Generate a "lui" instruction.
  586.  */
  587. static void
  588. macro_build_lui (counter, ep, regnum)
  589.      int *counter;
  590.      expressionS *ep;
  591.      int regnum;
  592. {
  593.   expressionS high_expr;
  594.   struct mips_cl_insn insn;
  595.   bfd_reloc_code_real_type r;
  596.   CONST char *name = "lui";
  597.   CONST char *fmt = "t,u";
  598.  
  599.   high_expr = *ep;
  600.  
  601.   if (high_expr.X_seg == &bfd_abs_section)
  602.     {
  603.       /* we can compute the instruction now without a relocation entry */
  604.       if (high_expr.X_add_number & 0x8000)
  605.     high_expr.X_add_number += 0x10000;
  606.       high_expr.X_add_number =
  607.     ((unsigned long) high_expr.X_add_number >> 16) & 0xffff;
  608.       r = BFD_RELOC_UNUSED;
  609.     }
  610.   else
  611.     r = BFD_RELOC_HI16_S;
  612.  
  613.   /*
  614.    * If the macro is about to expand into a second instruction,
  615.    * print a warning if needed. We need to pass ip as a parameter
  616.    * to generate a better warning message here...
  617.    */
  618.   if (mips_warn_about_macros && *counter == 1)
  619.     as_warn ("Macro instruction expanded into multiple instructions");
  620.  
  621.   *counter += 1;        /* bump instruction counter */
  622.  
  623.   insn.insn_mo = (struct mips_opcode *) hash_find (op_hash, name);
  624.   assert (insn.insn_mo);
  625.   assert (strcmp (name, insn.insn_mo->name) == 0);
  626.   assert (strcmp (fmt, insn.insn_mo->args) == 0);
  627.  
  628.   insn.insn_opcode = insn.insn_mo->match | (regnum << 16);
  629.   if (r == BFD_RELOC_UNUSED)
  630.     {
  631.       insn.insn_opcode |= high_expr.X_add_number;
  632.       append_insn (&insn, NULL, r);
  633.     }
  634.   else
  635.     append_insn (&insn, &high_expr, r);
  636. }
  637.  
  638. /*            set_at()
  639.  * Generates code to set the $at register to true (one)
  640.  * if reg is less than the immediate expression.
  641.  */
  642. static void
  643. set_at (counter, reg)
  644.      int *counter;
  645.      int reg;
  646. {
  647.  
  648.   switch (imm_expr.X_add_number & 0xffff8000)
  649.     {
  650.     case 0:
  651.     case 0xffff8000:
  652.       macro_build (counter, &imm_expr, "slti", "t,r,j", AT, reg);
  653.       return;
  654.  
  655.     case 0x8000:
  656.       macro_build (counter, &imm_expr, "ori", "t,r,i", AT, 0);
  657.       break;
  658.  
  659.     default:
  660.       macro_build_lui (counter, &imm_expr, AT);
  661.       if (imm_expr.X_add_number & 0xffff)
  662.     macro_build (counter, &imm_expr, "addiu", "t,r,j", AT, AT);
  663.     }
  664.   macro_build (counter, NULL, "slt", "d,v,t", AT, reg, AT);
  665. }
  666.  
  667. /*            set_at_unsigned()
  668.  * Generates code to set the $at register to true (one)
  669.  * if reg is less than the immediate expression.
  670.  * Unsigned comparison is perfomed.
  671.  */
  672. static void
  673. set_at_unsigned (counter, reg)
  674.      int *counter;
  675.      int reg;
  676. {
  677.  
  678.   switch (imm_expr.X_add_number & 0xffff8000)
  679.     {
  680.     case 0:
  681.     case 0xffff8000:
  682.       macro_build (counter, &imm_expr, "sltiu", "t,r,j", AT, reg);
  683.       return;
  684.  
  685.     case 0x8000:
  686.       macro_build (counter, &imm_expr, "ori", "t,r,i", AT, 0);
  687.       break;
  688.  
  689.     default:
  690.       macro_build_lui (counter, &imm_expr, AT);
  691.       if (imm_expr.X_add_number & 0xffff)
  692.     macro_build (counter, &imm_expr, "addiu", "t,r,j", AT, AT);
  693.     }
  694.   macro_build (counter, NULL, "sltu", "d,v,t", AT, reg, AT);
  695. }
  696.  
  697. static void
  698. check_absolute_expr (ip, expr)
  699.      struct mips_cl_insn *ip;
  700.      expressionS *expr;
  701. {
  702.  
  703.   if (expr->X_seg != &bfd_abs_section)
  704.     as_warn ("Instruction %s requires absolute expression", ip->insn_mo->name);
  705. }
  706.  
  707. /*            load_register()
  708.  *  This routine generates the least number of instructions neccessary to load
  709.  *  an absolute expression value into a register.
  710.  */
  711. static void
  712. load_register (counter, ip, reg, ep)
  713.      int *counter;
  714.      struct mips_cl_insn *ip;
  715.      int reg;
  716.      expressionS *ep;
  717. {
  718.   switch (ep->X_add_number & 0xffff8000)
  719.     {
  720.     case 0:
  721.     case 0xffff8000:
  722.       macro_build (counter, ep, "addiu", "t,r,j", reg, 0);
  723.       break;
  724.  
  725.     case 0x8000:
  726.       macro_build (counter, ep, "ori", "t,r,i", reg, 0);
  727.       break;
  728.  
  729.     default:
  730.       macro_build_lui (counter, ep, reg);
  731.       if (ep->X_add_number & 0xffff)
  732.     macro_build (counter, ep, "addiu", "t,r,j", reg, reg);
  733.     }
  734. }
  735.  
  736.  
  737. /*
  738.  *            Build macros
  739.  *   This routine implements the seemingly endless macro or synthesized
  740.  * instructions and addressing modes in the mips assembly language. Many
  741.  * of these macros are simple and are similar to each other. These could
  742.  * probably be handled by some kind of table or grammer aproach instead of
  743.  * this verbose method. Others are not simple macros but are more like
  744.  * optimizing code generation.
  745.  *   One interesting optimization is when several store macros appear
  746.  * consecutivly that would load AT with the upper half of the same address.
  747.  * The ensuing load upper instructions are ommited. This implies some kind
  748.  * of global optimization. We currently only optimize within a single macro.
  749.  *   For many of the load and store macros if the address is specified as a
  750.  * constant expression in the first 64k of memory (ie ld $2,0x4000c) we
  751.  * first load register 'at' with zero and use it as the base register. The
  752.  * mips assembler simply uses register $zero. Just one tiny optimization
  753.  * we're missing.
  754.  */
  755. static void
  756. macro (ip)
  757.      struct mips_cl_insn *ip;
  758. {
  759.   register int treg, sreg, dreg, breg;
  760.   int tempreg;
  761.   int mask;
  762.   int icnt = 0;
  763.   int used_at;
  764.   int save_reorder_condition;
  765.   expressionS expr1;
  766.   const char *s;
  767.   const char *fmt;
  768.  
  769.   treg = (ip->insn_opcode >> 16) & 0x1f;
  770.   dreg = (ip->insn_opcode >> 11) & 0x1f;
  771.   sreg = breg = (ip->insn_opcode >> 21) & 0x1f;
  772.   mask = ip->insn_mo->mask;
  773.  
  774.   expr1.X_seg = &bfd_abs_section;
  775.   expr1.X_subtract_symbol = NULL;
  776.   expr1.X_add_symbol = NULL;
  777.   expr1.X_add_number = 1;
  778.  
  779.   switch (mask)
  780.     {
  781.     case M_ABS:
  782.     case M_ABSU:
  783.       /*
  784.     Note: mips algorithm requires the move in the delay slot.
  785.     <main>:        bgez $a0,0x4001bc <main+12>
  786.     <main+4>:    move v0,$a0
  787.     <main+8>:    sub v0,$zero,$a0
  788.     <main+12>:    nop
  789.     */
  790.  
  791.       save_reorder_condition = mips_noreorder;
  792.       mips_noreorder = 1;
  793.  
  794.       expr1.X_add_number = 8;
  795.       macro_build (&icnt, &expr1, "bgez", "s,p", sreg);
  796.       macro_build (&icnt, NULL, "move", "d,s", dreg, sreg, 0);
  797.       macro_build (&icnt, NULL, mask == M_ABS ? "sub" : "subu", "d,v,t",
  798.            dreg, 0, sreg);
  799.  
  800.       mips_noreorder = save_reorder_condition;
  801.       return;
  802.  
  803.     case M_ADD_I:
  804.     case M_ADDU_I:
  805.       switch (imm_expr.X_add_number & 0xffff8000)
  806.     {
  807.     case 0:
  808.     case 0xffff8000:
  809.       macro_build (&icnt, &imm_expr,
  810.            mask == M_ADD_I ? "addi" : "addiu", "t,r,j", treg, sreg);
  811.       return;
  812.  
  813.     case 0x8000:
  814.       macro_build (&icnt, &imm_expr, "ori", "t,r,i", AT, 0);
  815.       break;
  816.  
  817.     default:
  818.       macro_build_lui (&icnt, &imm_expr, AT);
  819.       if (imm_expr.X_add_number & 0xffff)
  820.         macro_build (&icnt, &imm_expr, "addiu", "t,r,j", AT, AT);
  821.       break;
  822.     }
  823.       macro_build (&icnt, NULL,
  824.          mask == M_ADD_I ? "add" : "addu", "d,v,t", treg, sreg, AT);
  825.       break;
  826.  
  827.     case M_AND_I:
  828.     case M_OR_I:
  829.     case M_NOR_I:
  830.     case M_XOR_I:
  831.       switch (imm_expr.X_add_number & 0xffff8000)
  832.     {
  833.     case 0:
  834.     case 0x8000:
  835.       switch (mask)
  836.         {
  837.         case M_AND_I:
  838.           macro_build (&icnt, &imm_expr, "andi", "t,r,i", treg, sreg);
  839.           return;
  840.         case M_OR_I:
  841.           macro_build (&icnt, &imm_expr, "ori", "t,r,i", treg, sreg);
  842.           return;
  843.         case M_NOR_I:
  844.           macro_build (&icnt, &imm_expr, "ori", "t,r,i", treg, sreg);
  845.           macro_build (&icnt, &imm_expr, "nor", "d,v,t", treg, treg, 0);
  846.           return;
  847.         case M_XOR_I:
  848.           macro_build (&icnt, &imm_expr, "xori", "t,r,i", treg, sreg);
  849.           return;
  850.         default:
  851.           internalError ();
  852.         }
  853.  
  854.     case 0xffff8000:
  855.       macro_build (&icnt, &imm_expr, "addiu", "t,r,j", AT, 0);
  856.       break;
  857.  
  858.     default:
  859.       macro_build_lui (&icnt, &imm_expr, AT);
  860.       if (imm_expr.X_add_number & 0xffff)
  861.         macro_build (&icnt, &imm_expr, "addiu", "t,r,j", AT, AT);
  862.     }
  863.       switch (mask)
  864.     {
  865.     case M_AND_I:
  866.       macro_build (&icnt, NULL, "and", "d,v,t", treg, sreg, AT);
  867.       break;
  868.     case M_OR_I:
  869.       macro_build (&icnt, NULL, "or", "d,v,t", treg, sreg, AT);
  870.       break;
  871.     case M_NOR_I:
  872.       macro_build (&icnt, NULL, "nor", "d,v,t", treg, sreg, AT);
  873.       break;
  874.     case M_XOR_I:
  875.       macro_build (&icnt, NULL, "xor", "d,v,t", treg, sreg, AT);
  876.       break;
  877.     default:
  878.       internalError ();
  879.     }
  880.       break;
  881.  
  882.     case M_BEQ_I:
  883.     case M_BNE_I:
  884.       if (imm_expr.X_add_number == 0)
  885.     {
  886.       macro_build (&icnt, &offset_expr, mask == M_BEQ_I ? "beq" : "bne",
  887.                "s,t,p", sreg, 0);
  888.       return;
  889.     }
  890.       load_register (&icnt, ip, AT, &imm_expr);
  891.       macro_build (&icnt, &offset_expr, mask == M_BEQ_I ? "beq" : "bne",
  892.            "s,t,p", sreg, AT);
  893.       break;
  894.  
  895.     case M_BGE:
  896.       if (treg == 0)
  897.     {
  898.       macro_build (&icnt, &offset_expr, "bgez", "s,p", sreg);
  899.       return;
  900.     }
  901.       if (sreg == 0)
  902.     {
  903.       macro_build (&icnt, &offset_expr, "blez", "s,p", treg);
  904.       return;
  905.     }
  906.       macro_build (&icnt, NULL, "slt", "d,v,t", AT, sreg, treg);
  907.       macro_build (&icnt, &offset_expr, "beq", "s,t,p", AT, 0);
  908.       break;
  909.  
  910.     case M_BGT_I:
  911.       /* check for > max integer */
  912.       if (imm_expr.X_add_number == 0x7fffffff)
  913.     {
  914.     do_false:
  915.       /* result is always false */
  916.       as_warn ("Branch %s is always false (nop)", ip->insn_mo->name);
  917.       macro_build (&icnt, NULL, "nop", "", 0);
  918.       return;
  919.     }
  920.       imm_expr.X_add_number++;
  921.       /* FALLTHROUGH */
  922.  
  923.     case M_BGE_I:
  924.       if (imm_expr.X_add_number == 0)
  925.     {
  926.       macro_build (&icnt, &offset_expr, "bgez", "s,p", sreg);
  927.       return;
  928.     }
  929.       if (imm_expr.X_add_number == 1)
  930.     {
  931.       macro_build (&icnt, &offset_expr, "bgtz", "s,p", sreg);
  932.       return;
  933.     }
  934.       if (imm_expr.X_add_number == 0x80000000)
  935.     {
  936.     do_true:
  937.       /* result is always true */
  938.       as_warn ("Branch %s is always true", ip->insn_mo->name);
  939.       macro_build (&icnt, &offset_expr, "b", "p");
  940.       return;
  941.     }
  942.       set_at (&icnt, sreg);
  943.       macro_build (&icnt, &offset_expr, "beq", "s,t,p", AT, 0);
  944.       break;
  945.  
  946.     case M_BGEU:
  947.       if (treg == 0)
  948.     goto do_true;
  949.       if (sreg == 0)
  950.     {
  951.       macro_build (&icnt, &offset_expr, "beq", "s,t,p", 0, treg);
  952.       return;
  953.     }
  954.       macro_build (&icnt, NULL, "sltu", "d,v,t", AT, sreg, treg);
  955.       macro_build (&icnt, &offset_expr, "beq", "s,t,p", AT, 0);
  956.       break;
  957.  
  958.     case M_BGTU_I:
  959.       if (sreg == 0 || imm_expr.X_add_number == 0xffffffff)
  960.     goto do_false;
  961.       imm_expr.X_add_number++;
  962.       /* FALLTHROUGH */
  963.  
  964.     case M_BGEU_I:
  965.       if (imm_expr.X_add_number == 0)
  966.     goto do_true;
  967.       if (imm_expr.X_add_number == 1)
  968.     {
  969.       macro_build (&icnt, &offset_expr, "bne", "s,t,p", sreg, 0);
  970.       return;
  971.     }
  972.       set_at_unsigned (&icnt, sreg);
  973.       macro_build (&icnt, &offset_expr, "beq", "s,t,p", AT, 0);
  974.       break;
  975.  
  976.     case M_BGT:
  977.       if (treg == 0)
  978.     {
  979.       macro_build (&icnt, &offset_expr, "bgtz", "s,p", sreg);
  980.       return;
  981.     }
  982.       if (sreg == 0)
  983.     {
  984.       macro_build (&icnt, &offset_expr, "bltz", "s,p", treg);
  985.       return;
  986.     }
  987.       macro_build (&icnt, NULL, "slt", "d,v,t", AT, treg, sreg);
  988.       macro_build (&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
  989.       break;
  990.  
  991.     case M_BGTU:
  992.       if (treg == 0)
  993.     {
  994.       macro_build (&icnt, &offset_expr, "bne", "s,t,p", sreg, 0);
  995.       return;
  996.     }
  997.       if (sreg == 0)
  998.     goto do_false;
  999.       macro_build (&icnt, NULL, "sltu", "d,v,t", AT, treg, sreg);
  1000.       macro_build (&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
  1001.       break;
  1002.  
  1003.     case M_BLE:
  1004.       if (treg == 0)
  1005.     {
  1006.       macro_build (&icnt, &offset_expr, "blez", "s,p", sreg);
  1007.       return;
  1008.     }
  1009.       if (sreg == 0)
  1010.     {
  1011.       macro_build (&icnt, &offset_expr, "bgez", "s,p", treg);
  1012.       return;
  1013.     }
  1014.       macro_build (&icnt, NULL, "slt", "d,v,t", AT, treg, sreg);
  1015.       macro_build (&icnt, &offset_expr, "beq", "s,t,p", AT, 0);
  1016.       break;
  1017.  
  1018.     case M_BLE_I:
  1019.       if (imm_expr.X_add_number == 0x7fffffff)
  1020.     goto do_true;
  1021.       imm_expr.X_add_number++;
  1022.       /* FALLTHROUGH */
  1023.  
  1024.     case M_BLT_I:
  1025.       if (imm_expr.X_add_number == 0)
  1026.     {
  1027.       macro_build (&icnt, &offset_expr, "bltz", "s,p", sreg);
  1028.       return;
  1029.     }
  1030.       if (imm_expr.X_add_number == 1)
  1031.     {
  1032.       macro_build (&icnt, &offset_expr, "blez", "s,p", sreg);
  1033.       return;
  1034.     }
  1035.       set_at (&icnt, sreg);
  1036.       macro_build (&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
  1037.       break;
  1038.  
  1039.     case M_BLEU:
  1040.       if (treg == 0)
  1041.     {
  1042.       macro_build (&icnt, &offset_expr, "beq", "s,t,p", sreg, 0);
  1043.       return;
  1044.     }
  1045.       if (sreg == 0)
  1046.     goto do_true;
  1047.       macro_build (&icnt, NULL, "sltu", "d,v,t", AT, treg, sreg);
  1048.       macro_build (&icnt, &offset_expr, "beq", "s,t,p", AT, 0);
  1049.       break;
  1050.  
  1051.     case M_BLEU_I:
  1052.       if (sreg == 0 || imm_expr.X_add_number == 0xffffffff)
  1053.     goto do_true;
  1054.       imm_expr.X_add_number++;
  1055.       /* FALLTHROUGH */
  1056.  
  1057.     case M_BLTU_I:
  1058.       if (imm_expr.X_add_number == 0)
  1059.     goto do_false;
  1060.       if (imm_expr.X_add_number == 1)
  1061.     {
  1062.       macro_build (&icnt, &offset_expr, "beq", "s,t,p", sreg, 0);
  1063.       return;
  1064.     }
  1065.       set_at_unsigned (&icnt, sreg);
  1066.       macro_build (&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
  1067.       break;
  1068.  
  1069.     case M_BLT:
  1070.       if (treg == 0)
  1071.     {
  1072.       macro_build (&icnt, &offset_expr, "bltz", "s,p", sreg);
  1073.       return;
  1074.     }
  1075.       if (sreg == 0)
  1076.     {
  1077.       macro_build (&icnt, &offset_expr, "bgtz", "s,p", treg);
  1078.       return;
  1079.     }
  1080.       macro_build (&icnt, NULL, "slt", "d,v,t", AT, sreg, treg);
  1081.       macro_build (&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
  1082.       break;
  1083.  
  1084.     case M_BLTU:
  1085.       if (treg == 0)
  1086.     goto do_false;
  1087.       if (sreg == 0)
  1088.     {
  1089.       macro_build (&icnt, &offset_expr, "bne", "s,t,p", 0, treg);
  1090.       return;
  1091.     }
  1092.       macro_build (&icnt, NULL, "sltu", "d,v,t", AT, sreg, treg);
  1093.       macro_build (&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
  1094.       break;
  1095.  
  1096.     case M_DIV_3:
  1097.     case M_REM_3:
  1098.       if (treg == 0)
  1099.     {
  1100.       as_warn ("Divide by zero.");
  1101.       macro_build (&icnt, NULL, "break", "c", 7);
  1102.       return;
  1103.     }
  1104.  
  1105.       save_reorder_condition = mips_noreorder;
  1106.       mips_noreorder = 1;
  1107.       macro_build (&icnt, NULL, "div", "s,t", sreg, treg);
  1108.       expr1.X_add_number = 8;
  1109.       macro_build (&icnt, &expr1, "bne", "s,t,p", treg, 0);
  1110.       macro_build (&icnt, NULL, "nop", "", 0);
  1111.       macro_build (&icnt, NULL, "break", "c", 7);
  1112.       expr1.X_add_number = -1;
  1113.       macro_build (&icnt, &expr1, "addiu", "t,r,j", AT, 0);
  1114.       expr1.X_add_number = 16;
  1115.       macro_build (&icnt, &expr1, "bne", "s,t,p", treg, AT);
  1116.       expr1.X_add_number = 0x80000000;
  1117.       macro_build_lui (&icnt, &expr1, AT);
  1118.       expr1.X_add_number = 8;
  1119.       macro_build (&icnt, &expr1, "bne", "s,t,p", sreg, AT);
  1120.       macro_build (&icnt, NULL, "nop", "", 0);
  1121.       macro_build (&icnt, NULL, "break", "c", 6);
  1122.       mips_noreorder = save_reorder_condition;
  1123.       macro_build (&icnt, NULL, mask == M_DIV_3 ? "mflo" : "mfhi", "d", dreg);
  1124.       /* with reorder on there will be two implicit nop instructions here. */
  1125.       break;
  1126.  
  1127.     case M_DIV_3I:
  1128.     case M_DIVU_3I:
  1129.     case M_REM_3I:
  1130.     case M_REMU_3I:
  1131.       if (imm_expr.X_add_number == 0)
  1132.     {
  1133.       as_warn ("Divide by zero.");
  1134.       macro_build (&icnt, NULL, "break", "c", 7);
  1135.       return;
  1136.     }
  1137.       if (imm_expr.X_add_number == 1)
  1138.     {
  1139.       if (mask == (int) M_DIV_3I || mask == (int) M_DIVU_3I)
  1140.         macro_build (&icnt, NULL, "move", "d,s", dreg, sreg);
  1141.       else
  1142.         macro_build (&icnt, NULL, "move", "d,s", dreg, 0);
  1143.       return;
  1144.     }
  1145.  
  1146.       load_register (&icnt, ip, AT, &imm_expr);
  1147.       if (mask == (int) M_DIV_3I || mask == (int) M_REM_3I)
  1148.     macro_build (&icnt, NULL, "div", "s,t", sreg, AT);
  1149.       else
  1150.     macro_build (&icnt, NULL, "divu", "s,t", sreg, AT);
  1151.  
  1152.       if (mask == (int) M_DIV_3I || mask == (int) M_DIVU_3I)
  1153.     macro_build (&icnt, NULL, "mflo", "d", dreg);
  1154.       else
  1155.     macro_build (&icnt, NULL, "mfhi", "d", dreg);
  1156.       /* two implicit nop's required for mflo or mfhi */
  1157.       break;
  1158.  
  1159.     case M_DIVU_3:
  1160.     case M_REMU_3:
  1161.       save_reorder_condition = mips_noreorder;
  1162.       mips_noreorder = 1;
  1163.       macro_build (&icnt, NULL, "divu", "s,t", sreg, treg);
  1164.       expr1.X_add_number = 8;
  1165.       macro_build (&icnt, &expr1, "bne", "s,t,p", treg, 0);
  1166.       macro_build (&icnt, NULL, "nop", "", 0);
  1167.       macro_build (&icnt, NULL, "break", "c", 7);
  1168.       mips_noreorder = save_reorder_condition;
  1169.       macro_build (&icnt, NULL, mask == M_DIVU_3 ? "mflo" : "mfhi", "d", dreg);
  1170.       /* with reorder on there will be two implicit nop instructions here. */
  1171.       return;
  1172.  
  1173.     case M_LA:
  1174.       if (offset_expr.X_seg == &bfd_abs_section)
  1175.     {
  1176.       load_register (&icnt, ip, treg, &offset_expr);
  1177.       return;
  1178.     }
  1179.       if (gp_reference (&offset_expr))
  1180.     macro_build (&icnt, &offset_expr, "addiu", "t,r,j", treg, GP);
  1181.       else
  1182.     {
  1183.       macro_build_lui (&icnt, &offset_expr, treg);
  1184.       macro_build (&icnt, &offset_expr, "addiu", "t,r,j", treg, treg);
  1185.     }
  1186.       return;
  1187.  
  1188.     case M_LA_AB:
  1189.       tempreg = (breg == treg) ? AT : treg;
  1190.       if (offset_expr.X_seg == &bfd_abs_section)
  1191.     load_register (&icnt, ip, tempreg, &offset_expr);
  1192.       else if (gp_reference (&offset_expr))
  1193.     macro_build (&icnt, &offset_expr, "addiu", "t,r,j", tempreg, GP);
  1194.       else
  1195.     {
  1196.       macro_build_lui (&icnt, &offset_expr, tempreg);
  1197.       macro_build (&icnt, &offset_expr, "addiu", "t,r,j", tempreg, tempreg);
  1198.     }
  1199.       if (breg != 0)
  1200.     macro_build (&icnt, NULL, "addu", "d,v,t", treg, tempreg, breg);
  1201.       if (breg == treg)
  1202.     break;
  1203.       return;
  1204.  
  1205.     case M_LB_AB:
  1206.       s = "lb";
  1207.       goto ld;
  1208.     case M_LBU_AB:
  1209.       s = "lbu";
  1210.       goto ld;
  1211.     case M_LH_AB:
  1212.       s = "lh";
  1213.       goto ld;
  1214.     case M_LHU_AB:
  1215.       s = "lhu";
  1216.       goto ld;
  1217.     case M_LW_AB:
  1218.       s = "lw";
  1219.       goto ld;
  1220.     case M_LWC0_AB:
  1221.       s = "lwc0";
  1222.       goto ld;
  1223.     case M_LWC1_AB:
  1224.       s = "lwc1";
  1225.       goto ld;
  1226.     case M_LWC2_AB:
  1227.       s = "lwc2";
  1228.       goto ld;
  1229.     case M_LWC3_AB:
  1230.       s = "lwc3";
  1231.       goto ld;
  1232.     case M_LWL_AB:
  1233.       s = "lwl";
  1234.       goto ld;
  1235.     case M_LWR_AB:
  1236.       s = "lwr";
  1237.     ld:
  1238.       if (breg == treg || mask == M_LWC1_AB)
  1239.     {
  1240.       tempreg = AT;
  1241.       used_at = 1;
  1242.     }
  1243.       else
  1244.     {
  1245.       tempreg = treg;
  1246.       used_at = 0;
  1247.     }
  1248.       goto ld_st;
  1249.     case M_SB_AB:
  1250.       s = "sb";
  1251.       goto st;
  1252.     case M_SH_AB:
  1253.       s = "sh";
  1254.       goto st;
  1255.     case M_SW_AB:
  1256.       s = "sw";
  1257.       goto st;
  1258.     case M_SWC0_AB:
  1259.       s = "swc0";
  1260.       goto st;
  1261.     case M_SWC1_AB:
  1262.       s = "swc1";
  1263.       goto st;
  1264.     case M_SWC2_AB:
  1265.       s = "swc2";
  1266.       goto st;
  1267.     case M_SWC3_AB:
  1268.       s = "swc3";
  1269.       goto st;
  1270.     case M_SWL_AB:
  1271.       s = "swl";
  1272.       goto st;
  1273.     case M_SWR_AB:
  1274.       s = "swr";
  1275.     st:
  1276.       tempreg = AT;
  1277.       used_at = 1;
  1278.     ld_st:
  1279.       if (mask == M_LWC1_AB || mask == M_SWC1_AB)
  1280.     fmt = "T,o(b)";
  1281.       else
  1282.     fmt = "t,o(b)";
  1283.       if (gp_reference (&offset_expr))
  1284.     {
  1285.       if (breg == 0)
  1286.         {
  1287.           macro_build (&icnt, &offset_expr, s, fmt, treg, GP);
  1288.           return;
  1289.         }
  1290.       macro_build (&icnt, (expressionS *) NULL, "addu", "d,v,t",
  1291.                tempreg, breg, GP);
  1292.     }
  1293.       else
  1294.     {
  1295.       macro_build_lui (&icnt, &offset_expr, tempreg);
  1296.       if (breg != 0)
  1297.         macro_build (&icnt, NULL, "addu", "d,v,t", tempreg, tempreg, breg);
  1298.     }
  1299.       macro_build (&icnt, &offset_expr, s, fmt, treg, tempreg);
  1300.       if (used_at)
  1301.     break;
  1302.       return;
  1303.  
  1304.     case M_LI:
  1305.       load_register (&icnt, ip, treg, &imm_expr);
  1306.       return;
  1307.  
  1308.     case M_LI_D:
  1309.       /*
  1310.     0x400370 <main>:    lui $at,%hi(foo)
  1311.     0x400374 <main+4>:    lw $v0,%lo(foo)($at)
  1312.     0x400378 <main+8>:    lw $v1,%lo(foo+4)($at)
  1313.                 .data
  1314.          <foo>:
  1315.                 .float 3.133435
  1316.     */
  1317.       /* FIXME: I don't think this is used at present, because the 'F'
  1318.      format character is not supported.  When this is supported,
  1319.      it should use the GP register.  */
  1320.       macro_build_lui (&icnt, &offset_expr, AT);
  1321.       macro_build (&icnt, &offset_expr, "lw", "t,o(b)", treg, AT);
  1322.       offset_expr.X_add_number = 4;
  1323.       macro_build (&icnt, &offset_expr, "lw", "t,o(b)", treg + 1, AT);
  1324.       break;
  1325.  
  1326.     case M_LI_DD:
  1327.       /*
  1328.     0x4003a0 <main>:    lwc1 $f0,-32752($gp)
  1329.     0x4003a4 <main+4>:    lwc1 $f1,-32748($gp)
  1330.     0x4003a8 <main+8>:    nop
  1331.     */
  1332.       /* FIXME: This is nonsense.  It isn't used anyhow.  */
  1333.       sreg = (ip->insn_opcode >> 11) & 0x1f;    /* Fs reg */
  1334.       macro_build (&icnt, &offset_expr, "lwc1", "T,o(b)", treg, AT);
  1335.       offset_expr.X_add_number = 4;
  1336.       macro_build (&icnt, &offset_expr, "lwc1", "T,o(b)", treg + 1, AT);
  1337.       break;
  1338.  
  1339.     case M_L_DOB:
  1340.       /* Even on a big endian machine $fn comes before $fn+1.  We have
  1341.      to adjust when loading from memory.  */
  1342.       save_reorder_condition = mips_noreorder;
  1343.       mips_noreorder = 1;
  1344.       macro_build (&icnt, &offset_expr, "lwc1", "T,o(b)",
  1345.            byte_order == LITTLE_ENDIAN ? treg : treg + 1,
  1346.            breg);
  1347.       /* unecessary implicit nop */
  1348.       mips_noreorder = save_reorder_condition;
  1349.       offset_expr.X_add_number += 4;
  1350.       macro_build (&icnt, &offset_expr, "lwc1", "T,o(b)",
  1351.            byte_order == LITTLE_ENDIAN ? treg + 1 : treg,
  1352.            breg);
  1353.       return;
  1354.  
  1355.     case M_L_DAB:
  1356.       /*
  1357.        * The MIPS assembler seems to check for X_add_number not
  1358.        * being double aligned and generating:
  1359.        *    lui    at,%hi(foo+1)
  1360.        *    addu    at,at,v1
  1361.        *    addiu    at,at,%lo(foo+1)
  1362.        *    lwc1    f2,0(at)
  1363.        *    lwc1    f3,4(at)
  1364.        * But, the resulting address is the same after relocation so why
  1365.        * generate the extra instruction?
  1366.        */
  1367.       if (gp_reference (&offset_expr))
  1368.     {
  1369.       if (breg == 0)
  1370.         tempreg = GP;
  1371.       else
  1372.         {
  1373.           macro_build (&icnt, &offset_expr, "addu", "d,v,t", AT, breg, GP);
  1374.           tempreg = AT;
  1375.         }
  1376.     }
  1377.       else
  1378.     {
  1379.       macro_build_lui (&icnt, &offset_expr, AT);
  1380.       if (breg != 0)
  1381.         macro_build (&icnt, NULL, "addu", "d,v,t", AT, AT, breg);
  1382.       tempreg = AT;
  1383.     }
  1384.       /* Even on a big endian machine $fn comes before $fn+1.  We have
  1385.      to adjust when loading from memory.  */
  1386.       save_reorder_condition = mips_noreorder;
  1387.       mips_noreorder = 1;
  1388.       macro_build (&icnt, &offset_expr, "lwc1", "T,o(b)",
  1389.            byte_order == LITTLE_ENDIAN ? treg : treg + 1,
  1390.            tempreg);
  1391.       /* unecessary implicit nop */
  1392.       mips_noreorder = save_reorder_condition;
  1393.       offset_expr.X_add_number += 4;
  1394.       macro_build (&icnt, &offset_expr, "lwc1", "T,o(b)",
  1395.            byte_order == LITTLE_ENDIAN ? treg + 1 : treg,
  1396.            tempreg);
  1397.       if (tempreg == AT)
  1398.     break;
  1399.       return;
  1400.  
  1401.     case M_LD_OB:
  1402.       s = "lw";
  1403.       goto sd_ob;
  1404.     case M_SD_OB:
  1405.       s = "sw";
  1406.     sd_ob:
  1407.       macro_build (&icnt, &offset_expr, s, "t,o(b)", treg, breg);
  1408.       offset_expr.X_add_number = 4;
  1409.       macro_build (&icnt, &offset_expr, s, "t,o(b)", treg + 1, breg);
  1410.       return;
  1411.  
  1412.     case M_LD_AB:
  1413.       s = "lw";
  1414.       if (breg == treg)
  1415.     {
  1416.       tempreg = AT;
  1417.       used_at = 1;
  1418.     }
  1419.       else
  1420.     {
  1421.       tempreg = treg;
  1422.       used_at = 0;
  1423.     }
  1424.       goto sd_ab;
  1425.     case M_SD_AB:
  1426.       s = "sw";
  1427.       tempreg = AT;
  1428.       used_at = 1;
  1429.     sd_ab:
  1430.       if (gp_reference (&offset_expr))
  1431.     {
  1432.       if (breg == 0)
  1433.         {
  1434.           tempreg = GP;
  1435.           used_at = 0;
  1436.         }
  1437.       else
  1438.         macro_build (&icnt, (expressionS *) NULL, "addu", "d,v,t",
  1439.              tempreg, breg, GP);
  1440.     }
  1441.       else
  1442.     {
  1443.       macro_build_lui (&icnt, &offset_expr, tempreg);
  1444.       if (breg != 0)
  1445.         macro_build (&icnt, NULL, "addu", "d,v,t", tempreg, tempreg, breg);
  1446.     }
  1447.       macro_build (&icnt, &offset_expr, s, "t,o(b)", treg, tempreg);
  1448.       offset_expr.X_add_number += 4;
  1449.       macro_build (&icnt, &offset_expr, s, "t,o(b)", treg + 1, tempreg);
  1450.       if (used_at)
  1451.     break;
  1452.       return;
  1453.  
  1454.     case M_MUL:
  1455.       macro_build (&icnt, NULL, "multu", "s,t", sreg, treg);
  1456.       macro_build (&icnt, NULL, "mflo", "d", dreg);
  1457.       /* two implicit nop's required for mflo */
  1458.       return;
  1459.  
  1460.     case M_MUL_I:
  1461.       /*
  1462.        * The mips assembler some times generates shifts and adds.
  1463.        * Im not trying to be that fancy. GCC should do this for us
  1464.        * anyway.
  1465.        */
  1466.       load_register (&icnt, ip, AT, &imm_expr);
  1467.       macro_build (&icnt, NULL, "mult", "s,t", sreg, AT);
  1468.       macro_build (&icnt, NULL, "mflo", "d", dreg);
  1469.       /* two implicit nop's required for mflo */
  1470.       break;
  1471.  
  1472.     case M_ROL:
  1473.       macro_build (&icnt, NULL, "subu", "d,v,t", AT, 0, treg);
  1474.       macro_build (&icnt, NULL, "srlv", "d,t,s", AT, sreg, AT);
  1475.       macro_build (&icnt, NULL, "sllv", "d,t,s", dreg, sreg, treg);
  1476.       macro_build (&icnt, NULL, "or", "d,v,t", dreg, dreg, AT);
  1477.       break;
  1478.  
  1479.     case M_ROL_I:
  1480.       macro_build (&icnt, NULL, "sll", "d,w,<", AT, sreg,
  1481.            imm_expr.X_add_number & 0x1f);
  1482.       macro_build (&icnt, NULL, "srl", "d,w,<", dreg, sreg,
  1483.            (0 - imm_expr.X_add_number) & 0x1f);
  1484.       macro_build (&icnt, NULL, "or", "d,v,t", dreg, dreg, AT);
  1485.       break;
  1486.  
  1487.     case M_ROR:
  1488.       macro_build (&icnt, NULL, "subu", "d,v,t", AT, 0, treg);
  1489.       macro_build (&icnt, NULL, "sllv", "d,t,s", AT, sreg, AT);
  1490.       macro_build (&icnt, NULL, "srlv", "d,t,s", dreg, sreg, treg);
  1491.       macro_build (&icnt, NULL, "or", "d,v,t", dreg, dreg, AT);
  1492.       break;
  1493.  
  1494.     case M_ROR_I:
  1495.       macro_build (&icnt, NULL, "srl", "d,w,<", AT, sreg,
  1496.            imm_expr.X_add_number & 0x1f);
  1497.       macro_build (&icnt, NULL, "sll", "d,w,<", dreg, sreg,
  1498.            (0 - imm_expr.X_add_number) & 0x1f);
  1499.       macro_build (&icnt, NULL, "or", "d,v,t", dreg, dreg, AT);
  1500.       break;
  1501.  
  1502.     case M_S_DOB:
  1503.       /* Even on a big endian machine $fn comes before $fn+1.  We have
  1504.      to adjust when storing to memory.  */
  1505.       macro_build (&icnt, &offset_expr, "swc1", "T,o(b)",
  1506.            byte_order == LITTLE_ENDIAN ? treg : treg + 1,
  1507.            breg);
  1508.       offset_expr.X_add_number += 4;
  1509.       macro_build (&icnt, &offset_expr, "swc1", "T,o(b)",
  1510.            byte_order == LITTLE_ENDIAN ? treg + 1 : treg,
  1511.            breg);
  1512.       return;
  1513.  
  1514.     case M_S_DAB:
  1515.       if (gp_reference (&offset_expr))
  1516.     {
  1517.       if (breg == 0)
  1518.         tempreg = GP;
  1519.       else
  1520.         {
  1521.           macro_build (&icnt, (expressionS *) NULL, "addu", "d,v,t",
  1522.                AT, breg, GP);
  1523.           tempreg = AT;
  1524.         }
  1525.     }
  1526.       else
  1527.     {
  1528.       macro_build_lui (&icnt, &offset_expr, AT);
  1529.       if (breg != 0)
  1530.         macro_build (&icnt, NULL, "addu", "d,v,t", AT, AT, breg);
  1531.       tempreg = AT;
  1532.     }
  1533.       /* Even on a big endian machine $fn comes before $fn+1.  We have
  1534.      to adjust when storing to memory.  */
  1535.       macro_build (&icnt, &offset_expr, "swc1", "T,o(b)",
  1536.            byte_order == LITTLE_ENDIAN ? treg : treg + 1,
  1537.            tempreg);
  1538.       offset_expr.X_add_number += 4;
  1539.       macro_build (&icnt, &offset_expr, "swc1", "T,o(b)",
  1540.            byte_order == LITTLE_ENDIAN ? treg + 1 : treg,
  1541.            tempreg);
  1542.       if (tempreg == AT)
  1543.     break;
  1544.       return;
  1545.  
  1546.     case M_SEQ:
  1547.       if (sreg == 0)
  1548.     macro_build (&icnt, &expr1, "sltiu", "t,r,j", dreg, treg);
  1549.       else if (treg == 0)
  1550.     macro_build (&icnt, &expr1, "sltiu", "t,r,j", dreg, sreg);
  1551.       else
  1552.     {
  1553.       macro_build (&icnt, NULL, "xor", "d,v,t", dreg, sreg, treg);
  1554.       macro_build (&icnt, &expr1, "sltiu", "t,r,j", dreg, dreg);
  1555.     }
  1556.       return;
  1557.  
  1558.     case M_SEQ_I:
  1559.       if (imm_expr.X_add_number == 0)
  1560.     {
  1561.       macro_build (&icnt, &expr1, "sltiu", "t,r,j", dreg, sreg);
  1562.       return;
  1563.     }
  1564.       if (sreg == 0)
  1565.     {
  1566.       as_warn ("Instruction %s: result is always false",
  1567.         ip->insn_mo->name);
  1568.       macro_build (&icnt, NULL, "move", "d,s", dreg, 0);
  1569.       return;
  1570.     }
  1571.       switch (imm_expr.X_add_number & 0xffff8000)
  1572.     {
  1573.     case 0:
  1574.     case 0x8000:
  1575.       macro_build (&icnt, &imm_expr, "xori", "t,r,i", dreg, sreg);
  1576.       used_at = 0;
  1577.       break;
  1578.  
  1579.     case 0xffff8000:
  1580.       if (imm_expr.X_add_number != -32768)
  1581.         {
  1582.           imm_expr.X_add_number = -imm_expr.X_add_number;
  1583.           macro_build (&icnt, &imm_expr, "addiu", "t,r,j", dreg, sreg);
  1584.           used_at = 0;
  1585.           break;
  1586.         }
  1587.       /* FALLTHROUGH */
  1588.  
  1589.     default:
  1590.       macro_build_lui (&icnt, &imm_expr, AT);
  1591.       if (imm_expr.X_add_number & 0xffff)
  1592.         macro_build (&icnt, &imm_expr, "addiu", "t,r,j", AT, AT);
  1593.       macro_build (&icnt, NULL, "xor", "d,v,t", dreg, sreg, AT);
  1594.       used_at = 1;
  1595.     }
  1596.       macro_build (&icnt, &expr1, "sltiu", "t,r,j", dreg, dreg);
  1597.       if (used_at)
  1598.     break;
  1599.       return;
  1600.  
  1601.     case M_SGE:        /* sreg >= treg <==> not (sreg < treg) */
  1602.       s = "slt";
  1603.       goto sge;
  1604.     case M_SGEU:
  1605.       s = "sltu";
  1606.     sge:
  1607.       macro_build (&icnt, NULL, s, "d,v,t", dreg, sreg, treg);
  1608.       macro_build (&icnt, &expr1, "xori", "t,r,i", dreg, dreg);
  1609.       return;
  1610.  
  1611.     case M_SGE_I:        /* sreg >= I <==> not (sreg < I) */
  1612.     case M_SGEU_I:
  1613.       if (imm_expr.X_add_number < 32768 && imm_expr.X_add_number > -32769)
  1614.     {
  1615.       macro_build (&icnt, &expr1,
  1616.            mask == M_SGE_I ? "slti" : "sltiu", "t,r,j", dreg, sreg);
  1617.       used_at = 0;
  1618.     }
  1619.       else
  1620.     {
  1621.       load_register (&icnt, ip, AT, &imm_expr);
  1622.       macro_build (&icnt, NULL,
  1623.          mask == M_SGE_I ? "slt" : "sltu", "d,v,t", dreg, sreg, AT);
  1624.       used_at = 1;
  1625.     }
  1626.       macro_build (&icnt, &expr1, "xori", "t,r,i", dreg, dreg);
  1627.       if (used_at)
  1628.     break;
  1629.       return;
  1630.  
  1631.     case M_SGT:        /* sreg > treg  <==>  treg < sreg */
  1632.       s = "slt";
  1633.       goto sgt;
  1634.     case M_SGTU:
  1635.       s = "sltu";
  1636.     sgt:
  1637.       macro_build (&icnt, NULL, s, "d,v,t", dreg, treg, sreg);
  1638.       return;
  1639.  
  1640.     case M_SGT_I:        /* sreg > I  <==>  I < sreg */
  1641.       s = "slt";
  1642.       goto sgti;
  1643.     case M_SGTU_I:
  1644.       s = "sltu";
  1645.     sgti:
  1646.       load_register (&icnt, ip, AT, &imm_expr);
  1647.       macro_build (&icnt, NULL, s, "d,v,t", dreg, AT, sreg);
  1648.       break;
  1649.  
  1650.     case M_SLE:        /* sreg <= treg  <==>  treg >= sreg  <==>  not (treg < sreg) */
  1651.       s = "slt";
  1652.       goto sle;
  1653.     case M_SLEU:
  1654.       s = "sltu";
  1655.     sle:
  1656.       macro_build (&icnt, NULL, s, "d,v,t", dreg, treg, sreg);
  1657.       macro_build (&icnt, &expr1, "xori", "t,r,i", dreg, dreg);
  1658.       return;
  1659.  
  1660.     case M_SLE_I:        /* sreg <= I <==> I >= sreg <==> not (I < sreg) */
  1661.       s = "slt";
  1662.       goto slei;
  1663.     case M_SLEU_I:
  1664.       s = "sltu";
  1665.     slei:
  1666.       load_register (&icnt, ip, AT, &imm_expr);
  1667.       macro_build (&icnt, NULL, s, "d,v,t", dreg, AT, sreg);
  1668.       macro_build (&icnt, &expr1, "xori", "t,r,i", dreg, dreg);
  1669.       break;
  1670.  
  1671.     case M_SLT_I:
  1672.       if (imm_expr.X_add_number < 32768 && imm_expr.X_add_number > -32769)
  1673.     {
  1674.       macro_build (&icnt, &imm_expr, "slti", "t,r,j", dreg, sreg);
  1675.       return;
  1676.     }
  1677.       load_register (&icnt, ip, AT, &imm_expr);
  1678.       macro_build (&icnt, NULL, "slt", "d,v,t", dreg, sreg, AT);
  1679.       break;
  1680.  
  1681.     case M_SLTU_I:
  1682.       if (imm_expr.X_add_number < 32768 && imm_expr.X_add_number > -32769)
  1683.     {
  1684.       macro_build (&icnt, &imm_expr, "sltiu", "t,r,j", dreg, sreg);
  1685.       return;
  1686.     }
  1687.       load_register (&icnt, ip, AT, &imm_expr);
  1688.       macro_build (&icnt, NULL, "sltu", "d,v,t", dreg, sreg, AT);
  1689.       break;
  1690.  
  1691.     case M_SNE:
  1692.       if (sreg == 0)
  1693.     macro_build (&icnt, NULL, "sltu", "d,v,t", dreg, 0, treg);
  1694.       else if (treg == 0)
  1695.     macro_build (&icnt, NULL, "sltu", "d,v,t", dreg, 0, sreg);
  1696.       else
  1697.     {
  1698.       macro_build (&icnt, NULL, "xor", "d,v,t", dreg, sreg, treg);
  1699.       macro_build (&icnt, NULL, "sltu", "d,v,t", dreg, 0, dreg);
  1700.     }
  1701.       return;
  1702.  
  1703.     case M_SNE_I:
  1704.       if (imm_expr.X_add_number == 0)
  1705.     {
  1706.       macro_build (&icnt, NULL, "sltu", "d,v,t", dreg, 0, sreg);
  1707.       return;
  1708.     }
  1709.       if (sreg == 0)
  1710.     {
  1711.       as_warn ("Instruction %s: result is always true",
  1712.         ip->insn_mo->name);
  1713.       macro_build (&icnt, &expr1, "addiu", "t,r,j", dreg, 0);
  1714.       return;
  1715.     }
  1716.       switch (imm_expr.X_add_number & 0xffff8000)
  1717.     {
  1718.     case 0:
  1719.     case 0x8000:
  1720.       macro_build (&icnt, &imm_expr, "xori", "t,r,i", dreg, sreg);
  1721.       used_at = 0;
  1722.       break;
  1723.  
  1724.     case 0xffff8000:
  1725.       if (imm_expr.X_add_number != -32768)
  1726.         {
  1727.           imm_expr.X_add_number = -imm_expr.X_add_number;
  1728.           macro_build (&icnt, &imm_expr, "addiu", "t,r,j", dreg, sreg);
  1729.           used_at = 0;
  1730.           break;
  1731.         }
  1732.       /* FALLTHROUGH */
  1733.  
  1734.     default:
  1735.       macro_build_lui (&icnt, &imm_expr, AT);
  1736.       if (imm_expr.X_add_number & 0xffff)
  1737.         macro_build (&icnt, &imm_expr, "addiu", "t,r,j", AT, AT);
  1738.       macro_build (&icnt, NULL, "xor", "d,v,t", dreg, sreg, AT);
  1739.       used_at = 1;
  1740.     }
  1741.       macro_build (&icnt, NULL, "sltu", "d,v,t", dreg, 0, dreg);
  1742.       if (used_at)
  1743.     break;
  1744.       return;
  1745.  
  1746.     case M_SUB_I:
  1747.       if (imm_expr.X_add_number < 32768 && imm_expr.X_add_number > -32768)
  1748.     {
  1749.       imm_expr.X_add_number = -imm_expr.X_add_number;
  1750.       macro_build (&icnt, &imm_expr, "addi", "t,r,j", dreg, sreg);
  1751.       return;
  1752.     }
  1753.       load_register (&icnt, ip, AT, &imm_expr);
  1754.       macro_build (&icnt, NULL, "sub", "d,v,t", dreg, sreg, AT);
  1755.       break;
  1756.  
  1757.     case M_SUBU_I:
  1758.       if (imm_expr.X_add_number < 32768 && imm_expr.X_add_number > -32768)
  1759.     {
  1760.       imm_expr.X_add_number = -imm_expr.X_add_number;
  1761.       macro_build (&icnt, &imm_expr, "addiu", "t,r,j", dreg, sreg);
  1762.       return;
  1763.     }
  1764.       load_register (&icnt, ip, AT, &imm_expr);
  1765.       macro_build (&icnt, NULL, "subu", "d,v,t", dreg, sreg, AT);
  1766.       break;
  1767.  
  1768.     case M_TRUNCWD:
  1769.     case M_TRUNCWS:
  1770.       sreg = (ip->insn_opcode >> 11) & 0x1f;    /* floating reg */
  1771.       dreg = (ip->insn_opcode >> 06) & 0x1f;    /* floating reg */
  1772.  
  1773.       /*
  1774.        * Is the double cfc1 instruction a bug in the mips assembler;
  1775.        * or is there a reason for it?
  1776.        */
  1777.       save_reorder_condition = mips_noreorder;
  1778.       mips_noreorder = 1;
  1779.       macro_build (&icnt, NULL, "cfc1", "t,d", treg, 31);
  1780.       macro_build (&icnt, NULL, "cfc1", "t,d", treg, 31);
  1781.       macro_build (&icnt, NULL, "nop", "");
  1782.       expr1.X_add_number = 3;
  1783.       macro_build (&icnt, &expr1, "ori", "t,r,i", AT, treg);
  1784.       expr1.X_add_number = 2;
  1785.       macro_build (&icnt, &expr1, "xori", "t,r,i", AT, AT);
  1786.       macro_build (&icnt, NULL, "ctc1", "t,d", AT, 31);
  1787.       macro_build (&icnt, NULL, "nop", "");
  1788.       macro_build (&icnt, NULL,
  1789.           mask == M_TRUNCWD ? "cvt.w.d" : "cvt.w.s", "D,S", dreg, sreg);
  1790.       macro_build (&icnt, NULL, "ctc1", "t,d", treg, 31);
  1791.       macro_build (&icnt, NULL, "nop", "");
  1792.       mips_noreorder = save_reorder_condition;
  1793.       break;
  1794.  
  1795.     case M_ULH:
  1796.       s = "lb";
  1797.       goto ulh;
  1798.     case M_ULHU:
  1799.       s = "lbu";
  1800.     ulh:
  1801.       /* avoid load delay */
  1802.       offset_expr.X_add_number += 1;
  1803.       macro_build (&icnt, &offset_expr, s, "t,o(b)", treg, breg);
  1804.       offset_expr.X_add_number -= 1;
  1805.       macro_build (&icnt, &offset_expr, "lbu", "t,o(b)", AT, breg);
  1806.       macro_build (&icnt, NULL, "sll", "d,w,<", treg, treg, 8);
  1807.       macro_build (&icnt, NULL, "or", "d,v,t", treg, treg, AT);
  1808.       break;
  1809.  
  1810.     case M_ULW:
  1811.       /* does this work on a big endian machine? */
  1812.       offset_expr.X_add_number += 3;
  1813.       macro_build (&icnt, &offset_expr, "lwl", "t,o(b)", treg, breg);
  1814.       offset_expr.X_add_number -= 3;
  1815.       macro_build (&icnt, &offset_expr, "lwr", "t,o(b)", treg, breg);
  1816.       return;
  1817.  
  1818.     case M_ULH_A:
  1819.     case M_ULHU_A:
  1820.     case M_ULW_A:
  1821.       if (offset_expr.X_seg == &bfd_abs_section)
  1822.     load_register (&icnt, ip, AT, &offset_expr);
  1823.       else if (gp_reference (&offset_expr))
  1824.     macro_build (&icnt, &offset_expr, "addiu", "t,r,j", AT, GP);
  1825.       else
  1826.     {
  1827.       macro_build_lui (&icnt, &offset_expr, AT);
  1828.       macro_build (&icnt, &offset_expr, "addiu", "t,r,j", AT, AT);
  1829.     }
  1830.       if (mask == M_ULW_A)
  1831.     {
  1832.       expr1.X_add_number = 3;
  1833.       macro_build (&icnt, &expr1, "lwl", "t,o(b)", treg, AT);
  1834.       imm_expr.X_add_number = 0;
  1835.       macro_build (&icnt, &expr1, "lwr", "t,o(b)", treg, AT);
  1836.     }
  1837.       else
  1838.     {
  1839.       macro_build (&icnt, &expr1,
  1840.                mask == M_ULH_A ? "lb" : "lbu", "t,o(b)", treg, AT);
  1841.       imm_expr.X_add_number = 0;
  1842.       macro_build (&icnt, &expr1, "lbu", "t,o(b)", AT, AT);
  1843.       macro_build (&icnt, NULL, "sll", "d,w,<", treg, treg, 8);
  1844.       macro_build (&icnt, NULL, "or", "d,v,t", treg, treg, AT);
  1845.     }
  1846.       break;
  1847.  
  1848.     case M_USH:
  1849.       macro_build (&icnt, &offset_expr, "sb", "t,o(b)", treg, breg);
  1850.       macro_build (&icnt, NULL, "srl", "d,w,<", AT, treg, 8);
  1851.       offset_expr.X_add_number += 1;
  1852.       macro_build (&icnt, &offset_expr, "sb", "t,o(b)", AT, breg);
  1853.       break;
  1854.  
  1855.     case M_USW:
  1856.       offset_expr.X_add_number += 3;
  1857.       macro_build (&icnt, &offset_expr, "swl", "t,o(b)", treg, breg);
  1858.       offset_expr.X_add_number -= 3;
  1859.       macro_build (&icnt, &offset_expr, "swr", "t,o(b)", treg, breg);
  1860.       return;
  1861.  
  1862.     case M_USH_A:
  1863.     case M_USW_A:
  1864.       if (offset_expr.X_seg == &bfd_abs_section)
  1865.     load_register (&icnt, ip, AT, &offset_expr);
  1866.       else if (gp_reference (&offset_expr))
  1867.     macro_build (&icnt, &offset_expr, "addiu", "t,r,j", AT, GP);
  1868.       else
  1869.     {
  1870.       macro_build_lui (&icnt, &offset_expr, AT);
  1871.       macro_build (&icnt, &offset_expr, "addiu", "t,r,j", AT, AT);
  1872.     }
  1873.       if (mask == M_USW_A)
  1874.     {
  1875.       expr1.X_add_number = 3;
  1876.       macro_build (&icnt, &expr1, "swl", "t,o(b)", treg, AT);
  1877.       expr1.X_add_number = 0;
  1878.       macro_build (&icnt, &expr1, "swr", "t,o(b)", treg, AT);
  1879.     }
  1880.       else
  1881.     {
  1882.       expr1.X_add_number = 0;
  1883.       macro_build (&icnt, &expr1, "sb", "t,o(b)", treg, AT);
  1884.       macro_build (&icnt, NULL, "srl", "d,w,<", treg, treg, 8);
  1885.       expr1.X_add_number = 1;
  1886.       macro_build (&icnt, &expr1, "sb", "t,o(b)", treg, AT);
  1887.       expr1.X_add_number = 0;
  1888.       macro_build (&icnt, &expr1, "lbu", "t,o(b)", AT, AT);
  1889.       macro_build (&icnt, NULL, "sll", "d,w,<", treg, treg, 8);
  1890.       macro_build (&icnt, NULL, "or", "d,v,t", treg, treg, AT);
  1891.     }
  1892.       break;
  1893.  
  1894.     default:
  1895.       as_bad ("Macro %s not implemented yet", ip->insn_mo->name);
  1896.     }
  1897.   if (mips_noat)
  1898.     as_warn ("Macro used $at after \".set noat\"");
  1899. }
  1900.  
  1901.  
  1902. /*
  1903. This routine assembles an instruction into its binary format.  As a side
  1904. effect it sets one of the global variables imm_reloc or offset_reloc to the
  1905. type of relocation to do if one of the operands is an address expression.
  1906. */
  1907. static void
  1908. mips_ip (str, ip)
  1909.      char *str;
  1910.      struct mips_cl_insn *ip;
  1911. {
  1912.   char *s;
  1913.   const char *args;
  1914.   char c;
  1915.   struct mips_opcode *insn;
  1916.   char *argsStart;
  1917.   unsigned int regno;
  1918.   unsigned int lastregno = 0;
  1919.   char *s_reset;
  1920.  
  1921.   insn_error = NULL;
  1922.  
  1923.   for (s = str; islower (*s) || (*s >= '0' && *s <= '3') || *s == '.'; ++s)
  1924.     continue;
  1925.   switch (*s)
  1926.     {
  1927.     case '\0':
  1928.       break;
  1929.  
  1930.     case ' ':
  1931.       *s++ = '\0';
  1932.       break;
  1933.  
  1934.     default:
  1935.       as_warn ("Unknown opcode: `%s'", str);
  1936.       exit (1);
  1937.     }
  1938.   if ((insn = (struct mips_opcode *) hash_find (op_hash, str)) == NULL)
  1939.     {
  1940.       as_warn ("`%s' not in hash table.", str);
  1941.       insn_error = "ERROR: Unrecognized opcode";
  1942.       return;
  1943.     }
  1944.   argsStart = s;
  1945.   for (;;)
  1946.     {
  1947.       assert (strcmp (insn->name, str) == 0);
  1948.       ip->insn_mo = insn;
  1949.       ip->insn_opcode = insn->match;
  1950.       for (args = insn->args;; ++args)
  1951.     {
  1952.       if (*s == ' ')
  1953.         ++s;
  1954.       switch (*args)
  1955.         {
  1956.         case '\0':        /* end of args */
  1957.           if (*s == '\0')
  1958.         return;
  1959.           break;
  1960.  
  1961.         case ',':
  1962.           if (*s++ == *args)
  1963.         continue;
  1964.           s--;
  1965.           switch (*++args)
  1966.         {
  1967.         case 'r':
  1968.         case 'v':
  1969.           ip->insn_opcode |= lastregno << 21;
  1970.           continue;
  1971.  
  1972.         case 'w':
  1973.         case 'W':
  1974.           ip->insn_opcode |= lastregno << 16;
  1975.           continue;
  1976.  
  1977.         case 'V':
  1978.           ip->insn_opcode |= lastregno << 11;
  1979.           continue;
  1980.         }
  1981.           break;
  1982.  
  1983.         case '(':
  1984.           /* handle optional base register.
  1985.          Either the base register is omitted or
  1986.          we must have a left paren. */
  1987.           /* this is dependent on the next operand specifier
  1988.          is a 'b' for base register */
  1989.           assert (args[1] == 'b');
  1990.           if (*s == '\0')
  1991.         return;
  1992.  
  1993.         case ')':        /* these must match exactly */
  1994.           if (*s++ == *args)
  1995.         continue;
  1996.           break;
  1997.  
  1998.         case '<':        /* must be at least one digit */
  1999.           /*
  2000.            * According to the manual, if the shift amount is greater
  2001.            * than 31 or less than 0 the the shift amount should be
  2002.            * mod 32. In reality the mips assembler issues an error.
  2003.            * We issue a warning and do the mod.
  2004.            */
  2005.           my_getExpression (&imm_expr, s);
  2006.           check_absolute_expr (ip, &imm_expr);
  2007.           if ((unsigned long) imm_expr.X_add_number > 31)
  2008.         {
  2009.           as_warn ("Improper shift amount (%d)",
  2010.                imm_expr.X_add_number);
  2011.           imm_expr.X_add_number = imm_expr.X_add_number % 32;
  2012.         }
  2013.           ip->insn_opcode |= imm_expr.X_add_number << 6;
  2014.           imm_expr.X_seg = absent_section;
  2015.           s = expr_end;
  2016.           continue;
  2017.  
  2018.         case 'c':        /* break code */
  2019.           my_getExpression (&imm_expr, s);
  2020.           check_absolute_expr (ip, &imm_expr);
  2021.           if ((unsigned) imm_expr.X_add_number > 1023)
  2022.         as_warn ("Illegal break code (%d)", imm_expr.X_add_number);
  2023.           ip->insn_opcode |= imm_expr.X_add_number << 16;
  2024.           imm_expr.X_seg = absent_section;
  2025.           s = expr_end;
  2026.           continue;
  2027.  
  2028.         case 'b':        /* base register */
  2029.         case 'd':        /* destination register */
  2030.         case 's':        /* source register */
  2031.         case 't':        /* target register */
  2032.         case 'r':        /* both target and source */
  2033.         case 'v':        /* both dest and source */
  2034.         case 'w':        /* both dest and target */
  2035.           s_reset = s;
  2036.           if (s[0] == '$')
  2037.         {
  2038.           if (isdigit (s[1]))
  2039.             {
  2040.               ++s;
  2041.               regno = 0;
  2042.               do
  2043.             {
  2044.               regno *= 10;
  2045.               regno += *s - '0';
  2046.               ++s;
  2047.             }
  2048.               while (isdigit (*s));
  2049.             }
  2050.           else if (s[1] == 'f' && s[2] == 'p')
  2051.             {
  2052.               s += 3;
  2053.               regno = 30;
  2054.             }
  2055.           else if (s[1] == 's' && s[2] == 'p')
  2056.             {
  2057.               s += 3;
  2058.               regno = 29;
  2059.             }
  2060.           else if (s[1] == 'g' && s[2] == 'p')
  2061.             {
  2062.               s += 3;
  2063.               regno = 28;
  2064.             }
  2065.           else if (s[1] == 'a' && s[2] == 't')
  2066.             {
  2067.               s += 3;
  2068.               regno = 1;
  2069.             }
  2070.           else
  2071.             goto notreg;
  2072.           if (regno > 31)
  2073.             as_bad ("Invalid register number (%d)", regno);
  2074.           if (regno == AT && !mips_noat)
  2075.             as_warn ("Used $at without \".set noat\"");
  2076.           c = *args;
  2077.           if (*s == ' ')
  2078.             s++;
  2079.           if (args[1] != *s)
  2080.             {
  2081.               if (c == 'r' || c == 'v' || c == 'w')
  2082.             {
  2083.               regno = lastregno;
  2084.               s = s_reset;
  2085.               args++;
  2086.             }
  2087.             }
  2088.           switch (c)
  2089.             {
  2090.             case 'r':
  2091.             case 's':
  2092.             case 'v':
  2093.             case 'b':
  2094.               ip->insn_opcode |= regno << 21;
  2095.               break;
  2096.             case 'd':
  2097.               ip->insn_opcode |= regno << 11;
  2098.               break;
  2099.             case 'w':
  2100.             case 't':
  2101.               ip->insn_opcode |= regno << 16;
  2102.             }
  2103.           lastregno = regno;
  2104.           continue;
  2105.         }
  2106.         notreg:
  2107.           switch (*args++)
  2108.         {
  2109.         case 'r':
  2110.         case 'v':
  2111.           ip->insn_opcode |= lastregno << 21;
  2112.           continue;
  2113.         case 'w':
  2114.           ip->insn_opcode |= lastregno << 16;
  2115.           continue;
  2116.         }
  2117.           break;
  2118.  
  2119.         case 'D':        /* floating point destination register */
  2120.         case 'S':        /* floating point source register */
  2121.         case 'T':        /* floating point target register */
  2122.         case 'V':
  2123.         case 'W':
  2124.           s_reset = s;
  2125.           if (s[0] == '$' && s[1] == 'f' && isdigit (s[2]))
  2126.         {
  2127.           s += 2;
  2128.           regno = 0;
  2129.           do
  2130.             {
  2131.               regno *= 10;
  2132.               regno += *s - '0';
  2133.               ++s;
  2134.             }
  2135.           while (isdigit (*s));
  2136.  
  2137.           if (regno > 31)
  2138.             as_bad ("Invalid float register number (%d)", regno);
  2139.  
  2140.           if ((regno & 1) &&
  2141.               !(strcmp (str, "mtc1") == 0 ||
  2142.             strcmp (str, "mfc1") == 0 ||
  2143.             strcmp (str, "lwc1") == 0 ||
  2144.             strcmp (str, "swc1") == 0))
  2145.             as_warn ("Float register should be even, was %d",
  2146.                  regno);
  2147.  
  2148.           c = *args;
  2149.           if (*s == ' ')
  2150.             s++;
  2151.           if (args[1] != *s)
  2152.             {
  2153.               if (c == 'V' || c == 'W')
  2154.             {
  2155.               regno = lastregno;
  2156.               s = s_reset;
  2157.               args++;
  2158.             }
  2159.             }
  2160.           switch (c)
  2161.             {
  2162.             case 'D':
  2163.               ip->insn_opcode |= regno << 6;
  2164.               break;
  2165.             case 'V':
  2166.             case 'S':
  2167.               ip->insn_opcode |= regno << 11;
  2168.               break;
  2169.             case 'W':
  2170.             case 'T':
  2171.               ip->insn_opcode |= regno << 16;
  2172.             }
  2173.           lastregno = regno;
  2174.           continue;
  2175.         }
  2176.           switch (*args++)
  2177.         {
  2178.         case 'V':
  2179.           ip->insn_opcode |= lastregno << 11;
  2180.           continue;
  2181.         case 'W':
  2182.           ip->insn_opcode |= lastregno << 16;
  2183.           continue;
  2184.         }
  2185.           break;
  2186.  
  2187.         case 'I':
  2188.           my_getExpression (&imm_expr, s);
  2189.           check_absolute_expr (ip, &imm_expr);
  2190.           s = expr_end;
  2191.           continue;
  2192.  
  2193.         case 'A':
  2194.           my_getExpression (&offset_expr, s);
  2195.           imm_reloc = BFD_RELOC_32;
  2196.           s = expr_end;
  2197.           continue;
  2198.  
  2199.         case 'F':
  2200.           as_bad ("Floating point constants only implemented for pseudo ops.");
  2201.           continue;
  2202.  
  2203.         case 'i':        /* 16 bit unsigned immediate */
  2204.         case 'j':        /* 16 bit signed immediate */
  2205.           imm_reloc = BFD_RELOC_LO16;
  2206.           c = my_getSmallExpression (&imm_expr, s);
  2207.           if (c)
  2208.         {
  2209.           if (c != 'l')
  2210.             {
  2211.               if (imm_expr.X_seg == &bfd_abs_section)
  2212.             imm_expr.X_add_number =
  2213.               (imm_expr.X_add_number >> 16) & 0xffff;
  2214.               else if (c == 'h')
  2215.             imm_reloc = BFD_RELOC_HI16_S;
  2216.               else
  2217.             imm_reloc = BFD_RELOC_HI16;
  2218.             }
  2219.         }
  2220.           else
  2221.         check_absolute_expr (ip, &imm_expr);
  2222.           if (*args == 'i')
  2223.         {
  2224.           if ((unsigned long) imm_expr.X_add_number > 65535)
  2225.             as_bad ("16 bit expression not in range 0..65535");
  2226.         }
  2227.           else
  2228.         {
  2229.           if (imm_expr.X_add_number < -32768 ||
  2230.               imm_expr.X_add_number > 32767)
  2231.             as_bad ("16 bit expression not in range -32768..32767");
  2232.         }
  2233.           s = expr_end;
  2234.           continue;
  2235.  
  2236.         case 'o':        /* 16 bit offset */
  2237.           c = my_getSmallExpression (&offset_expr, s);
  2238.           /*
  2239.            * If this value won't fit into a 16 bit offset, then
  2240.            * go find a macro that will generate the 32 bit offset
  2241.            * code pattern.
  2242.            */
  2243.           if ((offset_expr.X_add_symbol
  2244.            && offset_expr.X_seg != &bfd_abs_section)
  2245.           || offset_expr.X_subtract_symbol
  2246.           || offset_expr.X_add_number > 32767
  2247.           || offset_expr.X_add_number < -32768)
  2248.         break;
  2249.  
  2250.           offset_reloc = BFD_RELOC_LO16;
  2251.           if (c == 'h' || c == 'H')
  2252.         offset_expr.X_add_number =
  2253.           (offset_expr.X_add_number >> 16) & 0xffff;
  2254.           s = expr_end;
  2255.           continue;
  2256.  
  2257.         case 'p':        /* pc relative offset */
  2258.           offset_reloc = BFD_RELOC_16_PCREL_S2;
  2259.           my_getExpression (&offset_expr, s);
  2260.           s = expr_end;
  2261.           continue;
  2262.  
  2263.         case 'u':        /* upper 16 bits */
  2264.           c = my_getSmallExpression (&imm_expr, s);
  2265.           if ((unsigned long) imm_expr.X_add_number > 65535)
  2266.         as_bad ("lui expression not in range 0..65535");
  2267.           imm_reloc = BFD_RELOC_LO16;
  2268.           if (c)
  2269.         {
  2270.           if (c != 'l')
  2271.             {
  2272.               if (imm_expr.X_seg == &bfd_abs_section)
  2273.             imm_expr.X_add_number =
  2274.               (imm_expr.X_add_number >> 16) & 0xffff;
  2275.               else if (c == 'h')
  2276.             imm_reloc = BFD_RELOC_HI16_S;
  2277.               else
  2278.             imm_reloc = BFD_RELOC_HI16;
  2279.             }
  2280.         }
  2281.           s = expr_end;
  2282.           continue;
  2283.  
  2284.         case 'a':        /* 26 bit address */
  2285.           my_getExpression (&offset_expr, s);
  2286.           s = expr_end;
  2287.           offset_reloc = BFD_RELOC_MIPS_JMP;
  2288.           continue;
  2289.  
  2290.         default:
  2291.           fprintf (stderr, "bad char = '%c'\n", *args);
  2292.           internalError ();
  2293.         }
  2294.       break;
  2295.     }
  2296.       /* Args don't match.  */
  2297.       if (insn + 1 < &mips_opcodes[NUMOPCODES] &&
  2298.       !strcmp (insn->name, insn[1].name))
  2299.     {
  2300.       ++insn;
  2301.       s = argsStart;
  2302.       continue;
  2303.     }
  2304.       insn_error = "ERROR: Illegal operands";
  2305.       return;
  2306.     }
  2307. }
  2308.  
  2309. #define LP '('
  2310. #define RP ')'
  2311.  
  2312. static int
  2313. my_getSmallExpression (ep, str)
  2314.      expressionS *ep;
  2315.      char *str;
  2316. {
  2317.   char *sp;
  2318.   int c = 0;
  2319.  
  2320.   if (*str == ' ')
  2321.     str++;
  2322.   if (*str == LP
  2323.       || (*str == '%' &&
  2324.       ((str[1] == 'h' && str[2] == 'i')
  2325.        || (str[1] == 'H' && str[2] == 'I')
  2326.        || (str[1] == 'l' && str[2] == 'o'))
  2327.       && str[3] == LP))
  2328.     {
  2329.       if (*str == LP)
  2330.     c = 0;
  2331.       else
  2332.     {
  2333.       c = str[1];
  2334.       str += 3;
  2335.     }
  2336.  
  2337.       /*
  2338.        * A small expression may be followed by a base register.
  2339.        * Scan to the end of this operand, and then back over a possible
  2340.        * base register.  Then scan the small expression up to that
  2341.        * point.  (Based on code in sparc.c...)
  2342.        */
  2343.       for (sp = str; *sp && *sp != ','; sp++)
  2344.     ;
  2345.       if (sp - 4 >= str && sp[-1] == RP)
  2346.     {
  2347.       if (isdigit (sp[-2]))
  2348.         {
  2349.           for (sp -= 3; sp >= str && isdigit (*sp); sp--)
  2350.         ;
  2351.           if (*sp == '$' && sp > str && sp[-1] == LP)
  2352.         {
  2353.           sp--;
  2354.           goto do_it;
  2355.         }
  2356.         }
  2357.       else if (sp - 5 >= str
  2358.            && sp[-5] == LP
  2359.            && sp[-4] == '$'
  2360.            && ((sp[-3] == 'f' && sp[-2] == 'p')
  2361.                || (sp[-3] == 's' && sp[-2] == 'p')
  2362.                || (sp[-3] == 'g' && sp[-2] == 'p')
  2363.                || (sp[-3] == 'a' && sp[-2] == 't')))
  2364.         {
  2365.           sp -= 5;
  2366.         do_it:
  2367.           if (sp == str)
  2368.         {
  2369.           /* no expression means zero offset */
  2370.           if (c)
  2371.             {
  2372.               /* %xx(reg) is an error */
  2373.               ep->X_seg = absent_section;
  2374.               expr_end = str - 3;
  2375.             }
  2376.           else
  2377.             {
  2378.               ep->X_seg = &bfd_abs_section;
  2379.               expr_end = sp;
  2380.             }
  2381.           ep->X_add_symbol = NULL;
  2382.           ep->X_subtract_symbol = NULL;
  2383.           ep->X_add_number = 0;
  2384.         }
  2385.           else
  2386.         {
  2387.           *sp = '\0';
  2388.           my_getExpression (ep, str);
  2389.           *sp = LP;
  2390.         }
  2391.           return c;
  2392.         }
  2393.     }
  2394.     }
  2395.   my_getExpression (ep, str);
  2396.   return c;            /* => %hi or %lo encountered */
  2397. }
  2398.  
  2399. static void
  2400. my_getExpression (ep, str)
  2401.      expressionS *ep;
  2402.      char *str;
  2403. {
  2404.   char *save_in;
  2405.   asection *seg;
  2406.  
  2407.   save_in = input_line_pointer;
  2408.   input_line_pointer = str;
  2409.   seg = expression (ep);
  2410.   expr_end = input_line_pointer;
  2411.   input_line_pointer = save_in;
  2412. }
  2413.  
  2414. char *
  2415. md_atof (type, litP, sizeP)
  2416.      char type;
  2417.      char *litP;
  2418.      int *sizeP;
  2419. {
  2420.   internalError ();
  2421.   return NULL;
  2422. }
  2423.  
  2424. void
  2425. md_number_to_chars (buf, val, n)
  2426.      char *buf;
  2427.      long val;
  2428.      int n;
  2429. {
  2430.   switch (byte_order)
  2431.     {
  2432.     case LITTLE_ENDIAN:
  2433.       switch (n)
  2434.     {
  2435.     case 4:
  2436.       *buf++ = val;
  2437.       *buf++ = val >> 8;
  2438.       *buf++ = val >> 16;
  2439.       *buf = val >> 24;
  2440.       return;
  2441.  
  2442.     case 2:
  2443.       *buf++ = val;
  2444.       *buf = val >> 8;
  2445.       return;
  2446.  
  2447.     case 1:
  2448.       *buf = val;
  2449.       return;
  2450.  
  2451.     default:
  2452.       internalError ();
  2453.     }
  2454.  
  2455.     case BIG_ENDIAN:
  2456.       switch (n)
  2457.     {
  2458.     case 4:
  2459.       *buf++ = val >> 24;
  2460.       *buf++ = val >> 16;
  2461.     case 2:
  2462.       *buf++ = val >> 8;
  2463.     case 1:
  2464.       *buf = val;
  2465.       return;
  2466.  
  2467.     default:
  2468.       internalError ();
  2469.     }
  2470.  
  2471.     default:
  2472.       internalError ();
  2473.     }
  2474. }
  2475.  
  2476. int
  2477. md_parse_option (argP, cntP, vecP)
  2478.      char **argP;
  2479.      int *cntP;
  2480.      char ***vecP;
  2481. {
  2482.   /* Accept -nocpp but ignore it. */
  2483.   if (!strcmp (*argP, "nocpp"))
  2484.     {
  2485.       *argP += 5;
  2486.       return 1;
  2487.     }
  2488.  
  2489.   if (strcmp (*argP, "EL") == 0
  2490.       || strcmp (*argP, "EB") == 0)
  2491.     {
  2492.       /* FIXME: This breaks -L -EL.  */
  2493.       flagseen['L'] = 0;
  2494.       *argP = "";
  2495.       return 1;
  2496.     }
  2497.  
  2498. #ifdef OBJ_ECOFF
  2499.   if (**argP == 'G')
  2500.     {
  2501.       if ((*argP)[1] != '\0')
  2502.     g_switch_value = atoi (*argP + 1);
  2503.       else if (*cntP)
  2504.     {
  2505.       **vecP = (char *) NULL;
  2506.       (*cntP)--;
  2507.       (*vecP)++;
  2508.       g_switch_value = atoi (**vecP);
  2509.     }
  2510.       else
  2511.     as_warn ("Number expected after -G");
  2512.       *argP = "";
  2513.       return 1;
  2514.     }
  2515. #endif
  2516.   return 1;            /* pretend you parsed the character */
  2517. }
  2518.  
  2519. long
  2520. md_pcrel_from (fixP)
  2521.      fixS *fixP;
  2522. {
  2523.   /* return the address of the delay slot */
  2524.   return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
  2525. }
  2526.  
  2527. int
  2528. md_apply_fix (fixP, valueP)
  2529.      fixS *fixP;
  2530.      long *valueP;
  2531. {
  2532.   unsigned char *buf;
  2533.   long insn, value;
  2534.  
  2535.   assert (fixP->fx_size == 4);
  2536.  
  2537.   value = *valueP;
  2538.   fixP->fx_addnumber = value;    /* Remember value for tc_gen_reloc */
  2539.  
  2540.   switch (fixP->fx_r_type)
  2541.     {
  2542.     case BFD_RELOC_32:
  2543.     case BFD_RELOC_MIPS_JMP:
  2544.     case BFD_RELOC_HI16:
  2545.     case BFD_RELOC_HI16_S:
  2546.     case BFD_RELOC_LO16:
  2547.     case BFD_RELOC_MIPS_GPREL:
  2548.       /* Nothing needed to do. The value comes from the reloc entry */
  2549.       return 1;
  2550.  
  2551.     case BFD_RELOC_16_PCREL_S2:
  2552.       /*
  2553.        * We need to save the bits in the instruction since fixup_segment()
  2554.        * might be deleting the relocation entry (i.e., a branch within
  2555.        * the current segment).
  2556.        */
  2557.       if (value & 0x3)
  2558.     as_warn ("Branch to odd address (%x)", value);
  2559.       value >>= 2;
  2560.       if ((value & ~0xFFFF) && (value & ~0xFFFF) != (-1 & ~0xFFFF))
  2561.     as_bad ("Relocation overflow");
  2562.  
  2563.       /* update old instruction data */
  2564.       buf = (unsigned char *) (fixP->fx_where + fixP->fx_frag->fr_literal);
  2565.       switch (byte_order)
  2566.     {
  2567.     case LITTLE_ENDIAN:
  2568.       insn = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
  2569.       break;
  2570.  
  2571.     case BIG_ENDIAN:
  2572.       insn = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
  2573.       break;
  2574.  
  2575.     default:
  2576.       internalError ();
  2577.       return 0;
  2578.     }
  2579.       insn |= value & 0xFFFF;
  2580.       md_number_to_chars (buf, insn, 4);
  2581.       break;
  2582.  
  2583.     default:
  2584.       internalError ();
  2585.     }
  2586.   return 1;
  2587. }
  2588.  
  2589. #if 0
  2590. void
  2591. printInsn (oc)
  2592.      unsigned long oc;
  2593. {
  2594.   const struct mips_opcode *p;
  2595.   int treg, sreg, dreg, shamt;
  2596.   short imm;
  2597.   const char *args;
  2598.   int i;
  2599.  
  2600.   for (i = 0; i < NUMOPCODES; ++i)
  2601.     {
  2602.       p = &mips_opcodes[i];
  2603.       if (((oc & p->mask) == p->match) && (p->pinfo != INSN_MACRO))
  2604.     {
  2605.       printf ("%08lx %s\t", oc, p->name);
  2606.       treg = (oc >> 16) & 0x1f;
  2607.       sreg = (oc >> 21) & 0x1f;
  2608.       dreg = (oc >> 11) & 0x1f;
  2609.       shamt = (oc >> 6) & 0x1f;
  2610.       imm = oc;
  2611.       for (args = p->args;; ++args)
  2612.         {
  2613.           switch (*args)
  2614.         {
  2615.         case '\0':
  2616.           printf ("\n");
  2617.           break;
  2618.  
  2619.         case ',':
  2620.         case '(':
  2621.         case ')':
  2622.           printf ("%c", *args);
  2623.           continue;
  2624.  
  2625.         case 'r':
  2626.           assert (treg == sreg);
  2627.           printf ("$%d,$%d", treg, sreg);
  2628.           continue;
  2629.  
  2630.         case 'd':
  2631.           printf ("$%d", dreg);
  2632.           continue;
  2633.  
  2634.         case 't':
  2635.           printf ("$%d", treg);
  2636.           continue;
  2637.  
  2638.         case 'b':
  2639.         case 's':
  2640.           printf ("$%d", sreg);
  2641.           continue;
  2642.  
  2643.         case 'a':
  2644.           printf ("0x%08lx", oc & 0x1ffffff);
  2645.           continue;
  2646.  
  2647.         case 'i':
  2648.         case 'j':
  2649.         case 'o':
  2650.         case 'u':
  2651.           printf ("%d", imm);
  2652.           continue;
  2653.  
  2654.         case '<':
  2655.           printf ("$%d", shamt);
  2656.           continue;
  2657.  
  2658.         default:
  2659.           internalError ();
  2660.         }
  2661.           break;
  2662.         }
  2663.       return;
  2664.     }
  2665.     }
  2666.   printf ("%08lx  UNDEFINED\n", oc);
  2667. }
  2668. #endif
  2669.  
  2670. static symbolS *
  2671. get_symbol ()
  2672. {
  2673.   int c;
  2674.   char *name;
  2675.   symbolS *p;
  2676.  
  2677.   name = input_line_pointer;
  2678.   c = get_symbol_end ();
  2679.   p = (symbolS *) symbol_find_or_make (name);
  2680.   *input_line_pointer = c;
  2681.   return p;
  2682. }
  2683.  
  2684. static long
  2685. get_optional_absolute_expression ()
  2686. {
  2687.   expressionS exp;
  2688.   asection *s;
  2689.  
  2690.   s = expression (&exp);
  2691.   if (!(s == &bfd_abs_section || s == big_section || s == absent_section))
  2692.     {
  2693.       as_bad ("Bad Absolute Expression.");
  2694.     }
  2695.   return exp.X_add_number;
  2696. }
  2697.  
  2698. static void
  2699. s_align (x)
  2700.      int x;
  2701. {
  2702.   register int temp;
  2703.   register long temp_fill;
  2704.   long max_alignment = 15;
  2705.  
  2706.   /*
  2707.  
  2708.     o  Note that the assembler pulls down any immediately preceeding label
  2709.        to the aligned address.
  2710.     o  It's not documented but auto alignment is reinstated by
  2711.        a .align pseudo instruction.
  2712.     o  Note also that after auto alignment is turned off the mips assembler
  2713.        issues an error on attempt to assemble an improperly aligned data item.
  2714.        We don't.
  2715.  
  2716.     */
  2717.  
  2718.   temp = get_absolute_expression ();
  2719.   if (temp > max_alignment)
  2720.     as_bad ("Alignment too large: %d. assumed.", temp = max_alignment);
  2721.   else if (temp < 0)
  2722.     {
  2723.       as_warn ("Alignment negative: 0 assumed.");
  2724.       temp = 0;
  2725.     }
  2726.   if (*input_line_pointer == ',')
  2727.     {
  2728.       input_line_pointer++;
  2729.       temp_fill = get_absolute_expression ();
  2730.     }
  2731.   else
  2732.     temp_fill = 0;
  2733.   if (temp)
  2734.     {
  2735.       auto_align = 1;
  2736.       if (!need_pass_2)
  2737.     frag_align (temp, (int) temp_fill);
  2738.     }
  2739.   else
  2740.     {
  2741.       auto_align = 0;
  2742.     }
  2743.  
  2744.   record_alignment (now_seg, temp);
  2745.  
  2746.   demand_empty_rest_of_line ();
  2747. }
  2748.  
  2749. static void
  2750. s_change_sec (sec)
  2751.      int sec;
  2752. {
  2753.   switch (sec)
  2754.     {
  2755.     case 't':
  2756.       s_text ();
  2757.       break;
  2758.     case 'r':
  2759. #ifdef OBJ_ECOFF
  2760.       subseg_new (".rdata", (subsegT) get_absolute_expression ());
  2761.       break;
  2762. #else
  2763.       /* Fall through.  */
  2764. #endif
  2765.     case 'd':
  2766.       s_data ();
  2767.       break;
  2768.     case 'b':
  2769. #ifdef BFD_ASSEMBLER
  2770.       subseg_set (bss_section, (subsegT) get_absolute_expression ());
  2771. #else
  2772.       subseg_new (bss_section, (subsegT) get_absolute_expression ());
  2773. #endif
  2774.       demand_empty_rest_of_line ();
  2775.       break;
  2776.     case 's':
  2777. #ifdef OBJ_ECOFF
  2778.       subseg_new (".sdata", (subsegT) get_absolute_expression ());
  2779.       break;
  2780. #else
  2781.       as_bad ("Global pointers not supported; recompile -G 0");
  2782.       return;
  2783. #endif
  2784.     }
  2785.   auto_align = 1;
  2786. }
  2787.  
  2788. static void
  2789. s_cons (log_size)
  2790.      int log_size;
  2791. {
  2792.  
  2793.   if (log_size > 0 && auto_align)
  2794.     frag_align (log_size, 0);
  2795.   cons (1 << log_size);
  2796. }
  2797.  
  2798. static void
  2799. s_err (x)
  2800.      int x;
  2801. {
  2802.   as_fatal ("Encountered `.err', aborting assembly");
  2803. }
  2804.  
  2805. static void
  2806. s_extern (x)
  2807.      int x;
  2808. {
  2809.   long size;
  2810.   symbolS *symbolP;
  2811.  
  2812.   symbolP = get_symbol ();
  2813.   if (*input_line_pointer == ',')
  2814.     input_line_pointer++;
  2815.   size = get_optional_absolute_expression ();
  2816.   S_SET_VALUE (symbolP, size);
  2817.   S_SET_EXTERNAL (symbolP);
  2818.  
  2819. #ifdef OBJ_ECOFF
  2820.   /* ECOFF needs to distinguish a .comm symbol from a .extern symbol,
  2821.      so we use an additional ECOFF specific field.  */
  2822.   symbolP->ecoff_undefined = 1;
  2823. #endif
  2824. }
  2825.  
  2826. static void
  2827. s_float_cons (is_double)
  2828.      int is_double;
  2829. {
  2830.   char *f;
  2831.   short words[4];
  2832.   int error_code, repeat;
  2833.   extern FLONUM_TYPE generic_floating_point_number;
  2834.  
  2835.   if (auto_align)
  2836.     if (is_double)
  2837.       frag_align (3, 0);
  2838.     else
  2839.       frag_align (2, 0);
  2840.  
  2841.   SKIP_WHITESPACE ();
  2842.   if (!is_end_of_line[(unsigned char) *input_line_pointer])
  2843.     {
  2844.       do
  2845.     {
  2846.       error_code = atof_generic (&input_line_pointer, ".", EXP_CHARS,
  2847.                      &generic_floating_point_number);
  2848.       if (error_code)
  2849.         {
  2850.           if (error_code == ERROR_EXPONENT_OVERFLOW)
  2851.         as_warn ("Bad floating-point constant: exponent overflow");
  2852.           else
  2853.         as_warn ("Bad floating-point constant: unknown error code=%d.", error_code);
  2854.         }
  2855.  
  2856.       if (is_double)
  2857.         {
  2858.           gen_to_words ((LITTLENUM_TYPE *) words,
  2859.                 4 /* precision */ ,
  2860.                 11 /* exponent_bits */ );
  2861.         }
  2862.       else
  2863.         {
  2864.           gen_to_words ((LITTLENUM_TYPE *) words,
  2865.                 2 /* precision */ ,
  2866.                 8 /* exponent_bits */ );
  2867.         }
  2868.       if (*input_line_pointer == ':')
  2869.         {
  2870.           input_line_pointer++;
  2871.           repeat = get_absolute_expression ();
  2872.         }
  2873.       else
  2874.         {
  2875.           repeat = 1;
  2876.         }
  2877.       if (is_double)
  2878.         {
  2879.           f = frag_more (repeat * 8);
  2880.           for (; repeat--; f += 8)
  2881.         {
  2882.           md_number_to_chars (f + 6, words[0], 2);
  2883.           md_number_to_chars (f + 4, words[1], 2);
  2884.           md_number_to_chars (f + 2, words[2], 2);
  2885.           md_number_to_chars (f, words[3], 2);
  2886.         }
  2887.         }
  2888.       else
  2889.         {
  2890.           f = frag_more (repeat * 4);
  2891.           for (; repeat--; f += 4)
  2892.         {
  2893.           md_number_to_chars (f + 2, words[0], 2);
  2894.           md_number_to_chars (f, words[1], 2);
  2895.         }
  2896.         }
  2897.       SKIP_WHITESPACE ();
  2898.       if (*input_line_pointer != ',')
  2899.         break;
  2900.       input_line_pointer++;
  2901.       SKIP_WHITESPACE ();
  2902.     }
  2903.       while (1);
  2904.     }
  2905.   demand_empty_rest_of_line ();
  2906. }
  2907.  
  2908. static void
  2909. s_option (x)
  2910.      int x;
  2911. {
  2912.   if (strcmp (input_line_pointer, "O1") != 0
  2913.       && strcmp (input_line_pointer, "O2") != 0)
  2914.     as_warn ("Unrecognized option");
  2915.   demand_empty_rest_of_line ();
  2916. }
  2917.  
  2918. static void
  2919. s_mipsset (x)
  2920.      int x;
  2921. {
  2922.   char *name = input_line_pointer, ch;
  2923.  
  2924.   while (!is_end_of_line[(unsigned char) *input_line_pointer])
  2925.     input_line_pointer++;
  2926.   ch = *input_line_pointer;
  2927.   *input_line_pointer = '\0';
  2928.  
  2929.   if (strcmp (name, "reorder") == 0)
  2930.     {
  2931.       mips_noreorder = 0;
  2932.     }
  2933.   else if (strcmp (name, "noreorder") == 0)
  2934.     {
  2935.       mips_noreorder = 1;
  2936.     }
  2937.   else if (strcmp (name, "at") == 0)
  2938.     {
  2939.       mips_noat = 0;
  2940.     }
  2941.   else if (strcmp (name, "noat") == 0)
  2942.     {
  2943.       mips_noat = 1;
  2944.     }
  2945.   else if (strcmp (name, "macro") == 0)
  2946.     {
  2947.       mips_warn_about_macros = 0;
  2948.     }
  2949.   else if (strcmp (name, "nomacro") == 0)
  2950.     {
  2951.       if (mips_noreorder == 0)
  2952.     as_bad ("`noreorder' must be set before `nomacro'");
  2953.       mips_warn_about_macros = 1;
  2954.     }
  2955.   else if (strcmp (name, "move") == 0 || strcmp (name, "novolatile") == 0)
  2956.     {
  2957.       mips_nomove = 0;
  2958.     }
  2959.   else if (strcmp (name, "nomove") == 0 || strcmp (name, "volatile") == 0)
  2960.     {
  2961.       mips_nomove = 1;
  2962.     }
  2963.   else if (strcmp (name, "bopt") == 0)
  2964.     {
  2965.       mips_nobopt = 0;
  2966.     }
  2967.   else if (strcmp (name, "nobopt") == 0)
  2968.     {
  2969.       mips_nobopt = 1;
  2970.     }
  2971.   else
  2972.     {
  2973.       as_warn ("Tried to set unrecognized symbol: %s\n", name);
  2974.     }
  2975.   *input_line_pointer = ch;
  2976.   demand_empty_rest_of_line ();
  2977. }
  2978.  
  2979. int
  2980. tc_get_register ()
  2981. {
  2982.   int reg;
  2983.  
  2984.   SKIP_WHITESPACE ();
  2985.   if (*input_line_pointer++ != '$')
  2986.     {
  2987.       as_warn ("expected `$'");
  2988.       return 0;
  2989.     }
  2990.   if (isdigit ((unsigned char) *input_line_pointer))
  2991.     {
  2992.       reg = get_absolute_expression ();
  2993.       if (reg < 0 || reg >= 32)
  2994.     {
  2995.       as_warn ("Bad register number");
  2996.       reg = 0;
  2997.     }
  2998.     }
  2999.   else
  3000.     {
  3001.       if (strncmp (input_line_pointer, "fp", 2) == 0)
  3002.     reg = 30;
  3003.       else if (strncmp (input_line_pointer, "sp", 2) == 0)
  3004.     reg = 29;
  3005.       else if (strncmp (input_line_pointer, "gp", 2) == 0)
  3006.     reg = 28;
  3007.       else if (strncmp (input_line_pointer, "at", 2) == 0)
  3008.     reg = 1;
  3009.       else
  3010.     {
  3011.       as_warn ("Unrecognized register name");
  3012.       return 0;
  3013.     }
  3014.       input_line_pointer += 2;
  3015.     }
  3016.   return reg;
  3017. }
  3018.  
  3019. /*
  3020.  * Translate internal representation of relocation info to BFD target format.
  3021.  */
  3022. arelent *
  3023. tc_gen_reloc (section, fixp)
  3024.      asection *section;
  3025.      fixS *fixp;
  3026. {
  3027.   arelent *reloc;
  3028.  
  3029.   reloc = (arelent *) xmalloc (sizeof (arelent));
  3030.   assert (reloc != 0);
  3031.  
  3032.   reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
  3033.   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
  3034.   if (fixp->fx_pcrel == 0)
  3035.     reloc->addend = fixp->fx_addnumber;
  3036.   else
  3037. #ifdef OBJ_ELF
  3038.     reloc->addend = 0;
  3039. #else
  3040.     reloc->addend = -reloc->address;
  3041. #endif
  3042.   reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
  3043.   assert (reloc->howto != 0);
  3044.  
  3045. #ifdef OBJ_ECOFF
  3046.   /* FIXME: This does the right thing, but it's confusing.  There
  3047.      should be a more coherent approach, but I don't know what it
  3048.      would be.  */
  3049.   reloc->addend -=
  3050.     bfd_get_section_vma (stdoutput,
  3051.              bfd_get_section (fixp->fx_addsy->bsym));
  3052. #endif
  3053.  
  3054.   return reloc;
  3055. }
  3056.  
  3057. /* should never be called */
  3058. long
  3059. md_section_align (seg, addr)
  3060.      asection *seg;
  3061.      long addr;
  3062. {
  3063.   int align = bfd_get_section_alignment (stdoutput, seg);
  3064.  
  3065.   return ((addr + (1 << align) - 1) & (-1 << align));
  3066. }
  3067.  
  3068. int
  3069. md_estimate_size_before_relax (fragP, segtype)
  3070.      fragS *fragP;
  3071.      asection *segtype;
  3072. {
  3073.   as_fatal ("md_estimate_size_before_relax");
  3074.   return (1);
  3075. }                /* md_estimate_size_before_relax() */
  3076.  
  3077. #ifndef OBJ_ECOFF
  3078.  
  3079. /* These functions should really be defined by the object file format,
  3080.    since they are related to debugging information.  However, this
  3081.    code has to work for the a.out format, which does not define them,
  3082.    so we provide simple versions here.  These don't actually generate
  3083.    any debugging information, but they do simple checking and someday
  3084.    somebody may make them useful.  */
  3085.  
  3086. typedef struct loc
  3087. {
  3088.   struct loc *loc_next;
  3089.   unsigned long loc_fileno;
  3090.   unsigned long loc_lineno;
  3091.   unsigned long loc_offset;
  3092.   unsigned short loc_delta;
  3093.   unsigned short loc_count;
  3094. #if 0
  3095.   fragS *loc_frag;
  3096. #endif
  3097. }
  3098. locS;
  3099.  
  3100. typedef struct proc
  3101.   {
  3102.     struct proc *proc_next;
  3103.     struct symbol *proc_isym;
  3104.     struct symbol *proc_end;
  3105.     unsigned long proc_reg_mask;
  3106.     unsigned long proc_reg_offset;
  3107.     unsigned long proc_fpreg_mask;
  3108.     unsigned long proc_fpreg_offset;
  3109.     unsigned long proc_frameoffset;
  3110.     unsigned long proc_framereg;
  3111.     unsigned long proc_pcreg;
  3112.     locS *proc_iline;
  3113.     struct file *proc_file;
  3114.     int proc_index;
  3115.   }
  3116. procS;
  3117.  
  3118. typedef struct file
  3119.   {
  3120.     struct file *file_next;
  3121.     unsigned long file_fileno;
  3122.     struct symbol *file_symbol;
  3123.     struct symbol *file_end;
  3124.     struct proc *file_proc;
  3125.     int file_numprocs;
  3126.   }
  3127. fileS;
  3128.  
  3129. static struct obstack proc_frags;
  3130. static procS *proc_lastP;
  3131. static procS *proc_rootP;
  3132. static int numprocs;
  3133.  
  3134. static void
  3135. md_obj_begin ()
  3136. {
  3137.   obstack_begin (&proc_frags, 0x2000);
  3138. }
  3139.  
  3140. static void
  3141. md_obj_end ()
  3142. {
  3143.   /* check for premature end, nesting errors, etc */
  3144.   if (proc_lastP && proc_lastP->proc_end == NULL)
  3145.     as_warn ("missing `.end' at end of assembly");
  3146. }
  3147.  
  3148. extern char hex_value[];
  3149.  
  3150. static long
  3151. get_number ()
  3152. {
  3153.   int negative = 0;
  3154.   long val = 0;
  3155.  
  3156.   if (*input_line_pointer == '-')
  3157.     {
  3158.       ++input_line_pointer;
  3159.       negative = 1;
  3160.     }
  3161.   if (!isdigit (*input_line_pointer))
  3162.     as_bad ("Expected simple number.");
  3163.   if (input_line_pointer[0] == '0')
  3164.     {
  3165.       if (input_line_pointer[1] == 'x')
  3166.     {
  3167.       input_line_pointer += 2;
  3168.       while (isxdigit (*input_line_pointer))
  3169.         {
  3170.           val <<= 4;
  3171.           val |= hex_value[(int) *input_line_pointer++];
  3172.         }
  3173.       return negative ? -val : val;
  3174.     }
  3175.       else
  3176.     {
  3177.       ++input_line_pointer;
  3178.       while (isdigit (*input_line_pointer))
  3179.         {
  3180.           val <<= 3;
  3181.           val |= *input_line_pointer++ - '0';
  3182.         }
  3183.       return negative ? -val : val;
  3184.     }
  3185.     }
  3186.   if (!isdigit (*input_line_pointer))
  3187.     {
  3188.       printf (" *input_line_pointer == '%c' 0x%02x\n",
  3189.           *input_line_pointer, *input_line_pointer);
  3190.       as_warn ("Invalid number");
  3191.       return -1;
  3192.     }
  3193.   while (isdigit (*input_line_pointer))
  3194.     {
  3195.       val *= 10;
  3196.       val += *input_line_pointer++ - '0';
  3197.     }
  3198.   return negative ? -val : val;
  3199. }
  3200.  
  3201. /* The .file directive; just like the usual .file directive, but there
  3202.    is an initial number which is the ECOFF file index.  */
  3203.  
  3204. static void
  3205. s_file (x)
  3206.      int x;
  3207. {
  3208.   int line;
  3209.  
  3210.   line = get_number ();
  3211.   s_app_file ();
  3212. }
  3213.  
  3214.  
  3215. /* The .end directive.  */
  3216.  
  3217. static void
  3218. s_mipsend (x)
  3219.      int x;
  3220. {
  3221.   symbolS *p;
  3222.  
  3223.   if (!is_end_of_line[(unsigned char) *input_line_pointer])
  3224.     {
  3225.       p = get_symbol ();
  3226.       demand_empty_rest_of_line ();
  3227.     }
  3228.   else
  3229.     p = NULL;
  3230.   if (now_seg != text_section)
  3231.     as_warn (".end not in text section");
  3232.   if (!proc_lastP)
  3233.     {
  3234.       as_warn (".end and no .ent seen yet.");
  3235.       return;
  3236.     }
  3237.  
  3238.   if (p != NULL)
  3239.     {
  3240.       assert (S_GET_NAME (p));
  3241.       if (strcmp (S_GET_NAME (p), S_GET_NAME (proc_lastP->proc_isym)))
  3242.     as_warn (".end symbol does not match .ent symbol.");
  3243.     }
  3244.  
  3245.   proc_lastP->proc_end = (symbolS *) 1;
  3246. }
  3247.  
  3248. /* The .aent and .ent directives.  */
  3249.  
  3250. static void
  3251. s_ent (aent)
  3252.      int aent;
  3253. {
  3254.   int number = 0;
  3255.   procS *procP;
  3256.   symbolS *symbolP;
  3257.  
  3258.   symbolP = get_symbol ();
  3259.   if (*input_line_pointer == ',')
  3260.     input_line_pointer++;
  3261.   if (isdigit (*input_line_pointer) || *input_line_pointer == '-')
  3262.     number = get_number ();
  3263.   if (now_seg != text_section)
  3264.     as_warn (".ent or .aent not in text section.");
  3265.  
  3266.   if (!aent && proc_lastP && proc_lastP->proc_end == NULL)
  3267.     as_warn ("missing `.end'");
  3268.  
  3269.   if (!aent)
  3270.     {
  3271.       procP = (procS *) obstack_alloc (&proc_frags, sizeof (*procP));
  3272.       procP->proc_isym = symbolP;
  3273.       procP->proc_reg_mask = 0;
  3274.       procP->proc_reg_offset = 0;
  3275.       procP->proc_fpreg_mask = 0;
  3276.       procP->proc_fpreg_offset = 0;
  3277.       procP->proc_frameoffset = 0;
  3278.       procP->proc_framereg = 0;
  3279.       procP->proc_pcreg = 0;
  3280.       procP->proc_end = NULL;
  3281.       procP->proc_next = NULL;
  3282.       if (proc_lastP)
  3283.     proc_lastP->proc_next = procP;
  3284.       else
  3285.     proc_rootP = procP;
  3286.       proc_lastP = procP;
  3287.       numprocs++;
  3288.     }
  3289.   demand_empty_rest_of_line ();
  3290. }
  3291.  
  3292. /* The .frame directive.  */
  3293.  
  3294. static void
  3295. s_frame (x)
  3296.      int x;
  3297. {
  3298. #if 0
  3299.   char str[100];
  3300.   symbolS *symP;
  3301.   int frame_reg;
  3302.   int frame_off;
  3303.   int pcreg;
  3304.  
  3305.   frame_reg = tc_get_register ();
  3306.   if (*input_line_pointer == ',')
  3307.     input_line_pointer++;
  3308.   frame_off = get_optional_absolute_expression ();
  3309.   if (*input_line_pointer == ',')
  3310.     input_line_pointer++;
  3311.   pcreg = tc_get_register ();
  3312.  
  3313.   /* bob third eye */
  3314.   assert (proc_rootP);
  3315.   proc_rootP->proc_framereg = frame_reg;
  3316.   proc_rootP->proc_frameoffset = frame_off;
  3317.   proc_rootP->proc_pcreg = pcreg;
  3318.   /* bob macho .frame */
  3319.  
  3320.   /* We don't have to write out a frame stab for unoptimized code. */
  3321.   if (!(frame_reg == 30 && frame_off == 0))
  3322.     {
  3323.       if (!proc_lastP)
  3324.     as_warn ("No .ent for .frame to use.");
  3325.       (void) sprintf (str, "R%d;%d", frame_reg, frame_off);
  3326.       symP = symbol_new (str, N_VFP, 0, frag_now);
  3327.       S_SET_TYPE (symP, N_RMASK);
  3328.       S_SET_OTHER (symP, 0);
  3329.       S_SET_DESC (symP, 0);
  3330.       symP->sy_forward = proc_lastP->proc_isym;
  3331.       /* bob perhaps I should have used pseudo set */
  3332.     }
  3333.   demand_empty_rest_of_line ();
  3334. #endif
  3335. }
  3336.  
  3337. /* The .fmask and .mask directives.  */
  3338.  
  3339. static void
  3340. s_mask (reg_type)
  3341.      char reg_type;
  3342. {
  3343. #if 0
  3344.   char str[100], *strP;
  3345.   symbolS *symP;
  3346.   int i;
  3347.   unsigned int mask;
  3348.   int off;
  3349.  
  3350.   mask = get_number ();
  3351.   if (*input_line_pointer == ',')
  3352.     input_line_pointer++;
  3353.   off = get_absolute_expression ();
  3354.  
  3355.   /* bob only for coff */
  3356.   assert (proc_rootP);
  3357.   if (reg_type == 'F')
  3358.     {
  3359.       proc_rootP->proc_fpreg_mask = mask;
  3360.       proc_rootP->proc_fpreg_offset = off;
  3361.     }
  3362.   else
  3363.     {
  3364.       proc_rootP->proc_reg_mask = mask;
  3365.       proc_rootP->proc_reg_offset = off;
  3366.     }
  3367.  
  3368.   /* bob macho .mask + .fmask */
  3369.  
  3370.   /* We don't have to write out a mask stab if no saved regs. */
  3371.   if (!(mask == 0))
  3372.     {
  3373.       if (!proc_lastP)
  3374.     as_warn ("No .ent for .mask to use.");
  3375.       strP = str;
  3376.       for (i = 0; i < 32; i++)
  3377.     {
  3378.       if (mask % 2)
  3379.         {
  3380.           sprintf (strP, "%c%d,", reg_type, i);
  3381.           strP += strlen (strP);
  3382.         }
  3383.       mask /= 2;
  3384.     }
  3385.       sprintf (strP, ";%d,", off);
  3386.       symP = symbol_new (str, N_RMASK, 0, frag_now);
  3387.       S_SET_TYPE (symP, N_RMASK);
  3388.       S_SET_OTHER (symP, 0);
  3389.       S_SET_DESC (symP, 0);
  3390.       symP->sy_forward = proc_lastP->proc_isym;
  3391.       /* bob perhaps I should have used pseudo set */
  3392.     }
  3393. #endif
  3394. }
  3395.  
  3396. /* The .loc directive.  */
  3397.  
  3398. static void
  3399. s_loc (x)
  3400.      int x;
  3401. {
  3402. #if 0
  3403.   symbolS *symbolP;
  3404.   int lineno;
  3405.   int addroff;
  3406.  
  3407.   assert (now_seg == text_section);
  3408.  
  3409.   lineno = get_number ();
  3410.   addroff = obstack_next_free (&frags) - frag_now->fr_literal;
  3411.  
  3412.   symbolP = symbol_new ("", N_SLINE, addroff, frag_now);
  3413.   S_SET_TYPE (symbolP, N_SLINE);
  3414.   S_SET_OTHER (symbolP, 0);
  3415.   S_SET_DESC (symbolP, lineno);
  3416.   symbolP->sy_segment = now_seg;
  3417. #endif
  3418. }
  3419.  
  3420. #endif /* ! defined (OBJ_ECOFF) */
  3421.